diff --git a/.swiftlint.yml b/.swiftlint.yml index d455616..eca1903 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,12 +1,18 @@ # Basic Configuration opt_in_rules: +- anyobject_protocol - array_init - attributes - closure_end_indentation - closure_spacing +- collection_alignment - conditional_returns_on_newline +- contains_over_filter_count +- contains_over_filter_is_empty - contains_over_first_not_nil +- contains_over_range_nil_comparison - convenience_type +- empty_collection_literal - empty_count - empty_string - empty_xctest_method @@ -16,12 +22,19 @@ opt_in_rules: - fatal_error_message - file_header - file_name +- file_name_no_space - file_types_order - first_where +- flatmap_over_map_reduce - function_default_parameter_at_end +- identical_operands +- implicit_return - implicitly_unwrapped_optional -- is_disjoint +- indentation_width - joined_default_parameter +- last_where +- legacy_multiple +- legacy_random - let_var_whitespace - literal_expression_end_indentation - lower_acl_than_parent @@ -29,52 +42,55 @@ opt_in_rules: - modifier_order - multiline_arguments - multiline_arguments_brackets -- multiline_function_chains - multiline_literal_brackets - multiline_parameters - multiline_parameters_brackets -- nimble_operator +- nslocalizedstring_key - number_separator - object_literal - operator_usage_whitespace +- optional_enum_case_matching - overridden_super_call - override_in_extension - pattern_matching_keywords +- prefer_self_type_over_type_of_self - private_action - private_outlet - prohibited_super_call -- quick_discouraged_call -- quick_discouraged_focused_test -- quick_discouraged_pending_test +- reduce_into - redundant_nil_coalescing - redundant_type_annotation - single_test_class - sorted_first_last - sorted_imports +- static_operator +- strong_iboutlet - switch_case_on_newline +- toggle_bool - trailing_closure - type_contents_order - unavailable_function - unneeded_parentheses_in_closure_argument - untyped_error_in_catch +- unused_declaration +- unused_import - vertical_parameter_alignment_on_call - vertical_whitespace_between_cases - vertical_whitespace_closing_braces - vertical_whitespace_opening_braces +- xct_specific_matcher - yoda_condition -disabled_rules: -- force_cast -- todo -- type_name - included: -- Frameworks +- Sources - Tests excluded: - Tests/LinuxMain.swift +disabled_rules: + - todo + # Rule Configurations conditional_returns_on_newline: if_only: true @@ -85,41 +101,28 @@ explicit_type_interface: - local file_header: - required_pattern: | - \/\/ - \/\/ Created by [^\(\)\d\n]+ on \S{6,10}\. - \/\/ Copyright © \d{4} Flinesoft\. All rights reserved\. - \/\/ + required_pattern: \/\/ Copyright © \d{4} Flinesoft\. All rights reserved\. file_name: - suffix_pattern: "Extensions?|\\+.*" - -file_types_order: - order: - - supporting_type - - main_type - - extension + suffix_pattern: "Ext" identifier_name: + max_length: 60 excluded: - id + - db + - to line_length: 160 -type_contents_order: - order: - - case - - [type_alias, associated_type] - - subtype - - type_property - - instance_property - - ib_outlet - - initializer - - type_method - - view_life_cycle_method - - ib_action - - other_method - - subscript +nesting: + type_level: 3 + +trailing_comma: + mandatory_comma: true + +trailing_whitespace: + ignores_comments: false # Custom Rules custom_rules: @@ -141,15 +144,9 @@ custom_rules: name: "Class Name Suffix View Controller" message: "All `ViewController` subclasses should end on `ViewController`." severity: warning - closing_brace_whitespace: - included: ".*.swift" - regex: '(?:\n| {2,})\}\)? *\n *[^ \n\})\]s#"]' - name: "Closing Brace Whitespace" - message: "Empty line required after closing curly braces if code with same indentation follows." - severity: warning closure_params_parantheses: included: ".*.swift" - regex: '\{\s*\([^):]+\)\s*in' + regex: '\{\s*\((?!self)[^):]+\)\s*in' name: "Unnecessary Closure Params Parantheses" message: "Don't use parantheses around non-typed parameters in a closure." severity: warning @@ -173,9 +170,9 @@ custom_rules: severity: warning controller_class_name_suffix: included: ".*.swift" - regex: 'class +\w+(?\w+) *= *!\k(?=\s)' - name: "Toggle Bool" - message: "Use `toggle()` instead of toggling manually." + regex: '\/\/ TODO: [^\n]{0,14}\n|\/\/ TODO: \[\S{1,12}\]|\/\/ TODO: [^\[]|\/\/ TODO: \[.{13}[^\]]|\/\/ TODO: \[[^a-z]{2}|\/\/ TODO: \[.{2}[^_]|\/\/ TODO: \[.{7}[^-]|\/\/ TODO: \[.{10}[^-]' + name: "Todo Date" + message: "All TODOs should have a format with creator credentials & date of their creation documented like this: `// TODO: [cg_YYYY-MM-DD] `." severity: warning - too_much_indentation: + todo_uppercase: included: ".*.swift" - regex: '\n {0}[^\s\/][^\n]*[^,|&]\n+ {5,}\S|\n {4}[^\s\/][^\n]*[^,|&]\n+ {9,}\S|\n {8}[^\s\/][^\n]*[^,|&]\n+ {13,}\S|\n {12}[^\s\/][^\n]*[^,|&]\n+ {17,}\S|\n {16}[^\s\/][^\n]*[^,|&]\n+ {21,}\S|\n {20}[^\s\/][^\n]*[^,|&]\n+ {25,}\S' - name: "Too Much Indentation" - message: "Don't indent code by more than 4 whitespaces." + regex: '\/\/ ?tODO|\/\/ ?ToDO|\/\/ ?TOdO|\/\/ ?TODo|\/\/ ?todo|\/\/ ?Todo|\/\/ ?ToDo|\/\/ ?toDo' + name: "Todo Uppercase" + message: "All TODOs should be all-uppercased like this: `// TODO: [cg_YYYY-MM-DD] `." severity: warning - too_much_unindentation: + todo_whitespacing: included: ".*.swift" - regex: ' {28}[^\s\.](.|[^\n]*[^\)][^\ ][^\}])\n+ {0,23}[^\s\/]| {24}[^\s\.](.|[^\n]*[^\)][^\ ][^\}])\n+ {0,19}[^\s\/]| {20}[^\s\.](.|[^\n]*[^\)][^\ ][^\}])\n+ {0,15}[^\s\/]| {16}[^\s\.](.|[^\n]*[^\)][^\ ][^\}])\n+ {0,11}[^\s\/]| {12}[^\s\.](.|[^\n]*[^\)][^\ ][^\}])\n+ {0,7}[^\s\/]| {8}[^\s\.](.|[^\n]*[^\)][^\ ][^\}])\n+ {0,3}[^\s\/]' - name: "Too Much Unindentation" - message: "Don't unindent code by more than 4 whitespaces." + regex: '\/\/TODO|\/\/ TODO\s|\/\/ TODO:[^ ]|\/\/ TODO: |\/\/ TODO: \[[^\s]{0,10}\][^ ]' + name: "Todo Whitespace" + message: "All TODOs should exactly start like this (mind the whitespacing): `// TODO: [cg_YYYY-MM-DD] `." severity: warning tuple_index: included: ".*.swift" diff --git a/CHANGELOG.md b/CHANGELOG.md index 308283c..5abd583 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,21 @@ # Changelog All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). + +
+Formatting Rules for Entries +Each entry should use the following format: + +```markdown +- Summary of what was changed in a single line using past tense & followed by two whitespaces. + Issue: [#0](https://github.com/Flinesoft/HandySwift/issues/0) | PR: [#0](https://github.com/Flinesoft/HandySwift/pull/0) | Author: [Cihat Gündüz](https://github.com/Jeehut) +``` + +Note that at the end of the summary line, you need to add two whitespaces (` `) for correct rendering on GitHub. + +If needed, pluralize to `Tasks`, `PRs` or `Authors` and list multiple entries separated by `, `. Also, remove entries not needed in the second line. +
## [Unreleased] ### Added @@ -17,6 +31,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ### Security - None. +## [3.2.0] - 2020-03-27 +### Added +- New `DivisibleArithmetic` protocol which easily extends `average()` to Collections of `Double`, `Float` and `CGFloat`. + Issue: [#36](https://github.com/Flinesoft/HandySwift/issues/36) | PR: [#38](https://github.com/Flinesoft/HandySwift/pull/38) | Author: [David Knothe](https://github.com/knothed) +- Make most of the API `@inlinable` for increased real-time performance. + Issue: [#40](https://github.com/Flinesoft/HandySwift/issues/40) | PR: [#43](https://github.com/Flinesoft/HandySwift/pull/43) | Author: [David Knothe](https://github.com/knothed) +### Changed +- Allow `Int.init?(randomBelow:)` to use an arbitrary RandomNumberGenerator (instead of just the system one). + PR: [#44](https://github.com/Flinesoft/HandySwift/pull/44) | Author: [David Knothe](https://github.com/knothed) + ## [3.1.0] - 2019-09-01 ### Added - New `Comparable.clamped(to:)` and `Comparable.clamp(to:)` interfaces for any `Comparable`, e. g. `Int`. @@ -26,15 +50,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - New `Withable` protocol to init/copy objects and set properties in a convenient way on a single line. ### Changed - Upgraded to Swift 5 & Xcode 10.2. -### Deprecated -- None. ### Removed - Remove `ExpressibleByStringLiteral` conformance of `Regex` type to only allow initialization via `init(_:options:) throws` interface. -### Fixed -- None. -### Security -- None. - ## [2.8.0] - 2019-02-11 ### Added @@ -44,14 +61,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - New `fullRange` and `fullNSRange` computed properties on `String` ### Changed - Made some APIs available in wider contexts (like `sample` in `RandomAccessCollection` instead of `Array`) -### Deprecated -- None. -### Removed -- None. -### Fixed -- None. -### Security -- None. ## [2.7.0] - 2018-09-27 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 376d626..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,31 +0,0 @@ -# Contributing - -Bug reports and pull requests are welcome on GitHub at https://github.com/Flinesoft/HandySwift. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. - -## Getting Started - -This section will tell you how you can get started contributing to HandySwift. - -### Prerequisites - -Before you start developing, please make sure you have the following tools installed on your machine: - -- Xcode 10.0+ -- [SwiftLint](https://github.com/realm/SwiftLint) -- [ProjLint](https://github.com/JamitLabs/ProjLint) -- [Beak](https://github.com/yonaskolb/Beak) -- [Sourcery](https://github.com/krzysztofzablocki/Sourcery) - -### Useful Commands - -To **update the Linux tests** (required after adding/renaming/removing test methods): - -``` -beak run generateLinuxMain -``` - -This will make sure the Linux CI can also find and run all the tests. - -### Commit Messages - -Please also try to follow the same syntax and semantic in your **commit messages** (see rationale [here](http://chris.beams.io/posts/git-commit/)). diff --git a/HandySwift.podspec b/HandySwift.podspec index 3f67fa3..2105cee 100644 --- a/HandySwift.podspec +++ b/HandySwift.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "HandySwift" - s.version = "3.1.0" + s.version = "3.2.0" s.summary = "Handy Swift features that didn't make it into the Swift standard library" s.description = <<-DESC @@ -14,7 +14,7 @@ Pod::Spec.new do |s| s.license = { :type => "MIT", :file => "LICENSE" } s.author = { "Cihat Gündüz" => "cocoapods@cihatguenduez.de" } - s.social_media_url = "https://twitter.com/Dschee" + s.social_media_url = "https://twitter.com/Jeehut" s.ios.deployment_target = "8.0" s.osx.deployment_target = "10.10" @@ -23,6 +23,6 @@ Pod::Spec.new do |s| s.source = { :git => "https://github.com/Flinesoft/HandySwift.git", :tag => "#{s.version}" } s.source_files = "Sources/HandySwift/**/*.swift" s.framework = "Foundation" - s.swift_version = "5.0" + s.swift_version = "5.1" end diff --git a/HandySwift.xcodeproj/project.pbxproj b/HandySwift.xcodeproj/project.pbxproj index 4388538..35d8862 100644 --- a/HandySwift.xcodeproj/project.pbxproj +++ b/HandySwift.xcodeproj/project.pbxproj @@ -7,20 +7,29 @@ objects = { /* Begin PBXBuildFile section */ - 3F95C8D220F22A3C0045AFD0 /* CollectionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F95C8D120F22A3C0045AFD0 /* CollectionExtension.swift */; }; - 3F95C8D520F22DEE0045AFD0 /* CollectionExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F95C8D320F22DC60045AFD0 /* CollectionExtensionTests.swift */; }; - 3F95C8D620F22DEF0045AFD0 /* CollectionExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F95C8D320F22DC60045AFD0 /* CollectionExtensionTests.swift */; }; - 3F95C8D720F22DEF0045AFD0 /* CollectionExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F95C8D320F22DC60045AFD0 /* CollectionExtensionTests.swift */; }; - 8218E4D62211D193007AAAF3 /* NSRangeExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8218E4D52211D193007AAAF3 /* NSRangeExtension.swift */; }; - 8218E4D72211D193007AAAF3 /* NSRangeExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8218E4D52211D193007AAAF3 /* NSRangeExtension.swift */; }; - 8218E4D82211D193007AAAF3 /* NSRangeExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8218E4D52211D193007AAAF3 /* NSRangeExtension.swift */; }; - 8218E4DA2211D270007AAAF3 /* NSRangeExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8218E4D92211D270007AAAF3 /* NSRangeExtensionTests.swift */; }; - 8218E4DB2211D270007AAAF3 /* NSRangeExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8218E4D92211D270007AAAF3 /* NSRangeExtensionTests.swift */; }; - 8218E4DC2211D270007AAAF3 /* NSRangeExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8218E4D92211D270007AAAF3 /* NSRangeExtensionTests.swift */; }; + 2E18B292242DECCA000C7776 /* NSObjectExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E18B291242DECCA000C7776 /* NSObjectExt.swift */; }; + 2E18B293242DECCA000C7776 /* NSObjectExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E18B291242DECCA000C7776 /* NSObjectExt.swift */; }; + 2E18B294242DECCA000C7776 /* NSObjectExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E18B291242DECCA000C7776 /* NSObjectExt.swift */; }; + 2E18B296242DF436000C7776 /* NSObjectExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E18B295242DF436000C7776 /* NSObjectExtTests.swift */; }; + 2E18B297242DF436000C7776 /* NSObjectExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E18B295242DF436000C7776 /* NSObjectExtTests.swift */; }; + 2E18B298242DF436000C7776 /* NSObjectExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E18B295242DF436000C7776 /* NSObjectExtTests.swift */; }; + 3F95C8D220F22A3C0045AFD0 /* CollectionExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F95C8D120F22A3C0045AFD0 /* CollectionExt.swift */; }; + 3F95C8D520F22DEE0045AFD0 /* CollectionExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F95C8D320F22DC60045AFD0 /* CollectionExtTests.swift */; }; + 3F95C8D620F22DEF0045AFD0 /* CollectionExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F95C8D320F22DC60045AFD0 /* CollectionExtTests.swift */; }; + 3F95C8D720F22DEF0045AFD0 /* CollectionExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F95C8D320F22DC60045AFD0 /* CollectionExtTests.swift */; }; + 63651F90231BFF2000E022DA /* DivisibleArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63651F8F231BFF2000E022DA /* DivisibleArithmetic.swift */; }; + 63651F91231BFF2000E022DA /* DivisibleArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63651F8F231BFF2000E022DA /* DivisibleArithmetic.swift */; }; + 63651F92231BFF2800E022DA /* DivisibleArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63651F8F231BFF2000E022DA /* DivisibleArithmetic.swift */; }; + 8218E4D62211D193007AAAF3 /* NSRangeExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8218E4D52211D193007AAAF3 /* NSRangeExt.swift */; }; + 8218E4D72211D193007AAAF3 /* NSRangeExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8218E4D52211D193007AAAF3 /* NSRangeExt.swift */; }; + 8218E4D82211D193007AAAF3 /* NSRangeExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8218E4D52211D193007AAAF3 /* NSRangeExt.swift */; }; + 8218E4DA2211D270007AAAF3 /* NSRangeExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8218E4D92211D270007AAAF3 /* NSRangeExtTests.swift */; }; + 8218E4DB2211D270007AAAF3 /* NSRangeExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8218E4D92211D270007AAAF3 /* NSRangeExtTests.swift */; }; + 8218E4DC2211D270007AAAF3 /* NSRangeExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8218E4D92211D270007AAAF3 /* NSRangeExtTests.swift */; }; 823B2B351C24AAB7007B3CDD /* HandySwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 823B2B341C24AAB7007B3CDD /* HandySwift.h */; settings = {ATTRIBUTES = (Public, ); }; }; 823B2B3C1C24AAB7007B3CDD /* HandySwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 823B2B311C24AAB6007B3CDD /* HandySwift.framework */; }; - 823B2B4D1C24ABA4007B3CDD /* IntExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823B2B4C1C24ABA4007B3CDD /* IntExtension.swift */; }; - 823B2B501C24AC00007B3CDD /* IntExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823B2B4F1C24AC00007B3CDD /* IntExtensionTests.swift */; }; + 823B2B4D1C24ABA4007B3CDD /* IntExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823B2B4C1C24ABA4007B3CDD /* IntExt.swift */; }; + 823B2B501C24AC00007B3CDD /* IntExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823B2B4F1C24AC00007B3CDD /* IntExtTests.swift */; }; 8251AA2022786D460022B277 /* Withable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8251AA1F22786D460022B277 /* Withable.swift */; }; 8251AA2122786D460022B277 /* Withable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8251AA1F22786D460022B277 /* Withable.swift */; }; 8251AA2222786D460022B277 /* Withable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8251AA1F22786D460022B277 /* Withable.swift */; }; @@ -34,57 +43,57 @@ 825EFE001C33357000558497 /* HandySwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 823B2B341C24AAB7007B3CDD /* HandySwift.h */; settings = {ATTRIBUTES = (Public, ); }; }; 825EFE011C33357200558497 /* HandySwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 823B2B341C24AAB7007B3CDD /* HandySwift.h */; settings = {ATTRIBUTES = (Public, ); }; }; 825EFE021C33358400558497 /* SortedArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8258E4551C2E0C140031CBFF /* SortedArray.swift */; }; - 825EFE031C33358400558497 /* IntExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823B2B4C1C24ABA4007B3CDD /* IntExtension.swift */; }; - 825EFE051C33358400558497 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2911C2ED1A200F934A7 /* StringExtension.swift */; }; - 825EFE061C33358400558497 /* ArrayExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2951C2EE64900F934A7 /* ArrayExtension.swift */; }; + 825EFE031C33358400558497 /* IntExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823B2B4C1C24ABA4007B3CDD /* IntExt.swift */; }; + 825EFE051C33358400558497 /* StringExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2911C2ED1A200F934A7 /* StringExt.swift */; }; + 825EFE061C33358400558497 /* ArrayExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2951C2EE64900F934A7 /* ArrayExt.swift */; }; 825EFE081C33358500558497 /* SortedArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8258E4551C2E0C140031CBFF /* SortedArray.swift */; }; - 825EFE091C33358500558497 /* IntExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823B2B4C1C24ABA4007B3CDD /* IntExtension.swift */; }; - 825EFE0B1C33358500558497 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2911C2ED1A200F934A7 /* StringExtension.swift */; }; - 825EFE0C1C33358500558497 /* ArrayExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2951C2EE64900F934A7 /* ArrayExtension.swift */; }; + 825EFE091C33358500558497 /* IntExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823B2B4C1C24ABA4007B3CDD /* IntExt.swift */; }; + 825EFE0B1C33358500558497 /* StringExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2911C2ED1A200F934A7 /* StringExt.swift */; }; + 825EFE0C1C33358500558497 /* ArrayExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2951C2EE64900F934A7 /* ArrayExt.swift */; }; 825EFE0E1C3335A400558497 /* SortedArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8258E4581C2E1ACE0031CBFF /* SortedArrayTests.swift */; }; - 825EFE0F1C3335A400558497 /* IntExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823B2B4F1C24AC00007B3CDD /* IntExtensionTests.swift */; }; - 825EFE111C3335A400558497 /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2931C2ED5E000F934A7 /* StringExtensionTests.swift */; }; - 825EFE121C3335A400558497 /* ArrayExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2971C2EE95200F934A7 /* ArrayExtensionTests.swift */; }; + 825EFE0F1C3335A400558497 /* IntExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823B2B4F1C24AC00007B3CDD /* IntExtTests.swift */; }; + 825EFE111C3335A400558497 /* StringExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2931C2ED5E000F934A7 /* StringExtTests.swift */; }; + 825EFE121C3335A400558497 /* ArrayExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2971C2EE95200F934A7 /* ArrayExtTests.swift */; }; 825EFE141C3335A500558497 /* SortedArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8258E4581C2E1ACE0031CBFF /* SortedArrayTests.swift */; }; - 825EFE151C3335A500558497 /* IntExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823B2B4F1C24AC00007B3CDD /* IntExtensionTests.swift */; }; - 825EFE171C3335A500558497 /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2931C2ED5E000F934A7 /* StringExtensionTests.swift */; }; - 825EFE181C3335A500558497 /* ArrayExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2971C2EE95200F934A7 /* ArrayExtensionTests.swift */; }; + 825EFE151C3335A500558497 /* IntExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823B2B4F1C24AC00007B3CDD /* IntExtTests.swift */; }; + 825EFE171C3335A500558497 /* StringExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2931C2ED5E000F934A7 /* StringExtTests.swift */; }; + 825EFE181C3335A500558497 /* ArrayExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2971C2EE95200F934A7 /* ArrayExtTests.swift */; }; 826F69AC1C3895A300B2CC6B /* FrequencyTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826F69AB1C3895A300B2CC6B /* FrequencyTable.swift */; }; 826F69AD1C3895A300B2CC6B /* FrequencyTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826F69AB1C3895A300B2CC6B /* FrequencyTable.swift */; }; 826F69AE1C3895A300B2CC6B /* FrequencyTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826F69AB1C3895A300B2CC6B /* FrequencyTable.swift */; }; 826F69B01C389DB800B2CC6B /* FrequencyTableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826F69AF1C389DB800B2CC6B /* FrequencyTableTests.swift */; }; 826F69B11C389DB800B2CC6B /* FrequencyTableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826F69AF1C389DB800B2CC6B /* FrequencyTableTests.swift */; }; 826F69B21C389DB800B2CC6B /* FrequencyTableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826F69AF1C389DB800B2CC6B /* FrequencyTableTests.swift */; }; - 827599641E520FB800787F99 /* DispatchTimeIntervalExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827599631E520FB800787F99 /* DispatchTimeIntervalExtensionTests.swift */; }; - 827599651E520FB800787F99 /* DispatchTimeIntervalExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827599631E520FB800787F99 /* DispatchTimeIntervalExtensionTests.swift */; }; - 827599661E520FB800787F99 /* DispatchTimeIntervalExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827599631E520FB800787F99 /* DispatchTimeIntervalExtensionTests.swift */; }; - 8280D7DC1C4A6EC9001172EF /* DictionaryExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8280D7DB1C4A6EC9001172EF /* DictionaryExtension.swift */; }; - 8280D7DD1C4A6EC9001172EF /* DictionaryExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8280D7DB1C4A6EC9001172EF /* DictionaryExtension.swift */; }; - 8280D7DE1C4A6EC9001172EF /* DictionaryExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8280D7DB1C4A6EC9001172EF /* DictionaryExtension.swift */; }; - 8280D7E01C4A6FF3001172EF /* DictionaryExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8280D7DF1C4A6FF3001172EF /* DictionaryExtensionTests.swift */; }; - 8280D7E11C4A6FF3001172EF /* DictionaryExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8280D7DF1C4A6FF3001172EF /* DictionaryExtensionTests.swift */; }; - 8280D7E21C4A6FF3001172EF /* DictionaryExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8280D7DF1C4A6FF3001172EF /* DictionaryExtensionTests.swift */; }; + 827599641E520FB800787F99 /* DispatchTimeIntervalExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827599631E520FB800787F99 /* DispatchTimeIntervalExtTests.swift */; }; + 827599651E520FB800787F99 /* DispatchTimeIntervalExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827599631E520FB800787F99 /* DispatchTimeIntervalExtTests.swift */; }; + 827599661E520FB800787F99 /* DispatchTimeIntervalExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827599631E520FB800787F99 /* DispatchTimeIntervalExtTests.swift */; }; + 8280D7DC1C4A6EC9001172EF /* DictionaryExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8280D7DB1C4A6EC9001172EF /* DictionaryExt.swift */; }; + 8280D7DD1C4A6EC9001172EF /* DictionaryExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8280D7DB1C4A6EC9001172EF /* DictionaryExt.swift */; }; + 8280D7DE1C4A6EC9001172EF /* DictionaryExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8280D7DB1C4A6EC9001172EF /* DictionaryExt.swift */; }; + 8280D7E01C4A6FF3001172EF /* DictionaryExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8280D7DF1C4A6FF3001172EF /* DictionaryExtTests.swift */; }; + 8280D7E11C4A6FF3001172EF /* DictionaryExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8280D7DF1C4A6FF3001172EF /* DictionaryExtTests.swift */; }; + 8280D7E21C4A6FF3001172EF /* DictionaryExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8280D7DF1C4A6FF3001172EF /* DictionaryExtTests.swift */; }; 82812A9B1D06877B00CD5B6C /* Globals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82812A9A1D06877B00CD5B6C /* Globals.swift */; }; 82812A9C1D06877B00CD5B6C /* Globals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82812A9A1D06877B00CD5B6C /* Globals.swift */; }; 82812A9D1D06877B00CD5B6C /* Globals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82812A9A1D06877B00CD5B6C /* Globals.swift */; }; 82812A9F1D06926800CD5B6C /* GlobalsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82812A9E1D06926800CD5B6C /* GlobalsTests.swift */; }; 82812AA01D06926800CD5B6C /* GlobalsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82812A9E1D06926800CD5B6C /* GlobalsTests.swift */; }; 82812AA11D06926800CD5B6C /* GlobalsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82812A9E1D06926800CD5B6C /* GlobalsTests.swift */; }; - 82CAE2921C2ED1A200F934A7 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2911C2ED1A200F934A7 /* StringExtension.swift */; }; - 82CAE2941C2ED5E000F934A7 /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2931C2ED5E000F934A7 /* StringExtensionTests.swift */; }; - 82CAE2961C2EE64900F934A7 /* ArrayExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2951C2EE64900F934A7 /* ArrayExtension.swift */; }; - 82CAE2981C2EE95200F934A7 /* ArrayExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2971C2EE95200F934A7 /* ArrayExtensionTests.swift */; }; - 82E21E8E211AF9960061EB1B /* CollectionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F95C8D120F22A3C0045AFD0 /* CollectionExtension.swift */; }; - 82E21E8F211AF9970061EB1B /* CollectionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F95C8D120F22A3C0045AFD0 /* CollectionExtension.swift */; }; - A11830D31E589F6700CBE087 /* TimeIntervalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11830D21E589F6700CBE087 /* TimeIntervalExtension.swift */; }; - A11830D41E589F6700CBE087 /* TimeIntervalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11830D21E589F6700CBE087 /* TimeIntervalExtension.swift */; }; - A11830D51E589F6700CBE087 /* TimeIntervalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11830D21E589F6700CBE087 /* TimeIntervalExtension.swift */; }; - A11830D71E58A11D00CBE087 /* TimeIntervalExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11830D61E58A11D00CBE087 /* TimeIntervalExtensionTests.swift */; }; - A11830D81E58A11D00CBE087 /* TimeIntervalExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11830D61E58A11D00CBE087 /* TimeIntervalExtensionTests.swift */; }; - A11830D91E58A11D00CBE087 /* TimeIntervalExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11830D61E58A11D00CBE087 /* TimeIntervalExtensionTests.swift */; }; - A1F221641E3CC05100419B06 /* DispatchTimeIntervalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1F221631E3CC05100419B06 /* DispatchTimeIntervalExtension.swift */; }; - A1F221651E3CC05100419B06 /* DispatchTimeIntervalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1F221631E3CC05100419B06 /* DispatchTimeIntervalExtension.swift */; }; - A1F221661E3CC05100419B06 /* DispatchTimeIntervalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1F221631E3CC05100419B06 /* DispatchTimeIntervalExtension.swift */; }; + 82CAE2921C2ED1A200F934A7 /* StringExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2911C2ED1A200F934A7 /* StringExt.swift */; }; + 82CAE2941C2ED5E000F934A7 /* StringExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2931C2ED5E000F934A7 /* StringExtTests.swift */; }; + 82CAE2961C2EE64900F934A7 /* ArrayExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2951C2EE64900F934A7 /* ArrayExt.swift */; }; + 82CAE2981C2EE95200F934A7 /* ArrayExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAE2971C2EE95200F934A7 /* ArrayExtTests.swift */; }; + 82E21E8E211AF9960061EB1B /* CollectionExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F95C8D120F22A3C0045AFD0 /* CollectionExt.swift */; }; + 82E21E8F211AF9970061EB1B /* CollectionExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F95C8D120F22A3C0045AFD0 /* CollectionExt.swift */; }; + A11830D31E589F6700CBE087 /* TimeIntervalExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11830D21E589F6700CBE087 /* TimeIntervalExt.swift */; }; + A11830D41E589F6700CBE087 /* TimeIntervalExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11830D21E589F6700CBE087 /* TimeIntervalExt.swift */; }; + A11830D51E589F6700CBE087 /* TimeIntervalExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11830D21E589F6700CBE087 /* TimeIntervalExt.swift */; }; + A11830D71E58A11D00CBE087 /* TimeIntervalExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11830D61E58A11D00CBE087 /* TimeIntervalExtTests.swift */; }; + A11830D81E58A11D00CBE087 /* TimeIntervalExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11830D61E58A11D00CBE087 /* TimeIntervalExtTests.swift */; }; + A11830D91E58A11D00CBE087 /* TimeIntervalExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11830D61E58A11D00CBE087 /* TimeIntervalExtTests.swift */; }; + A1F221641E3CC05100419B06 /* DispatchTimeIntervalExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1F221631E3CC05100419B06 /* DispatchTimeIntervalExt.swift */; }; + A1F221651E3CC05100419B06 /* DispatchTimeIntervalExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1F221631E3CC05100419B06 /* DispatchTimeIntervalExt.swift */; }; + A1F221661E3CC05100419B06 /* DispatchTimeIntervalExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1F221631E3CC05100419B06 /* DispatchTimeIntervalExt.swift */; }; C5C89B9420B0A0C10048B07C /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5C89B9320B0A0C10048B07C /* Weak.swift */; }; C5CFB6AC20B0A70300830511 /* Unowned.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5CFB6AB20B0A70300830511 /* Unowned.swift */; }; C5CFB6AD20B0A70300830511 /* Unowned.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5CFB6AB20B0A70300830511 /* Unowned.swift */; }; @@ -97,12 +106,12 @@ CC4AE0CF2087D8A7009931F6 /* RegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC4AE0CD2087D895009931F6 /* RegexTests.swift */; }; CC4AE0D02087D8A8009931F6 /* RegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC4AE0CD2087D895009931F6 /* RegexTests.swift */; }; CC4AE0D12087D8A9009931F6 /* RegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC4AE0CD2087D895009931F6 /* RegexTests.swift */; }; - CC66E047228199A0007ABF61 /* ComparableExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC66E046228199A0007ABF61 /* ComparableExtension.swift */; }; - CC66E048228199DE007ABF61 /* ComparableExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC66E046228199A0007ABF61 /* ComparableExtension.swift */; }; - CC66E049228199DF007ABF61 /* ComparableExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC66E046228199A0007ABF61 /* ComparableExtension.swift */; }; - CC66E12522819FFF007ABF61 /* ComparableExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC66E12322819FCF007ABF61 /* ComparableExtensionTests.swift */; }; - CC66E1262281A000007ABF61 /* ComparableExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC66E12322819FCF007ABF61 /* ComparableExtensionTests.swift */; }; - CC66E1272281A000007ABF61 /* ComparableExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC66E12322819FCF007ABF61 /* ComparableExtensionTests.swift */; }; + CC66E047228199A0007ABF61 /* ComparableExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC66E046228199A0007ABF61 /* ComparableExt.swift */; }; + CC66E048228199DE007ABF61 /* ComparableExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC66E046228199A0007ABF61 /* ComparableExt.swift */; }; + CC66E049228199DF007ABF61 /* ComparableExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC66E046228199A0007ABF61 /* ComparableExt.swift */; }; + CC66E12522819FFF007ABF61 /* ComparableExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC66E12322819FCF007ABF61 /* ComparableExtTests.swift */; }; + CC66E1262281A000007ABF61 /* ComparableExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC66E12322819FCF007ABF61 /* ComparableExtTests.swift */; }; + CC66E1272281A000007ABF61 /* ComparableExtTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC66E12322819FCF007ABF61 /* ComparableExtTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -130,11 +139,14 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 2E18B291242DECCA000C7776 /* NSObjectExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSObjectExt.swift; sourceTree = ""; }; + 2E18B295242DF436000C7776 /* NSObjectExtTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSObjectExtTests.swift; sourceTree = ""; }; 2E4189DB231B971E00C65B81 /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = ""; }; - 3F95C8D120F22A3C0045AFD0 /* CollectionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionExtension.swift; sourceTree = ""; }; - 3F95C8D320F22DC60045AFD0 /* CollectionExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionExtensionTests.swift; sourceTree = ""; }; - 8218E4D52211D193007AAAF3 /* NSRangeExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSRangeExtension.swift; sourceTree = ""; }; - 8218E4D92211D270007AAAF3 /* NSRangeExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSRangeExtensionTests.swift; sourceTree = ""; }; + 3F95C8D120F22A3C0045AFD0 /* CollectionExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionExt.swift; sourceTree = ""; }; + 3F95C8D320F22DC60045AFD0 /* CollectionExtTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionExtTests.swift; sourceTree = ""; }; + 63651F8F231BFF2000E022DA /* DivisibleArithmetic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DivisibleArithmetic.swift; sourceTree = ""; }; + 8218E4D52211D193007AAAF3 /* NSRangeExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSRangeExt.swift; sourceTree = ""; }; + 8218E4D92211D270007AAAF3 /* NSRangeExtTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSRangeExtTests.swift; sourceTree = ""; }; 8218E4DD2211D7D3007AAAF3 /* CODE_OF_CONDUCT.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CODE_OF_CONDUCT.md; sourceTree = ""; }; 8218E4DE2211D7D3007AAAF3 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = ""; }; 8218E4DF2211D7D3007AAAF3 /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = ""; }; @@ -143,8 +155,8 @@ 823B2B361C24AAB7007B3CDD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 823B2B3B1C24AAB7007B3CDD /* HandySwift iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "HandySwift iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 823B2B421C24AAB7007B3CDD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 823B2B4C1C24ABA4007B3CDD /* IntExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntExtension.swift; sourceTree = ""; }; - 823B2B4F1C24AC00007B3CDD /* IntExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntExtensionTests.swift; sourceTree = ""; }; + 823B2B4C1C24ABA4007B3CDD /* IntExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntExt.swift; sourceTree = ""; }; + 823B2B4F1C24AC00007B3CDD /* IntExtTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntExtTests.swift; sourceTree = ""; }; 8251AA1F22786D460022B277 /* Withable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Withable.swift; sourceTree = ""; }; 8251AA24227875C00022B277 /* WithableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WithableTests.swift; sourceTree = ""; }; 8258E4551C2E0C140031CBFF /* SortedArray.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SortedArray.swift; sourceTree = ""; }; @@ -155,30 +167,30 @@ 825EFDF21C33351300558497 /* HandySwift tvOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "HandySwift tvOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 826F69AB1C3895A300B2CC6B /* FrequencyTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FrequencyTable.swift; sourceTree = ""; }; 826F69AF1C389DB800B2CC6B /* FrequencyTableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FrequencyTableTests.swift; sourceTree = ""; }; - 827599631E520FB800787F99 /* DispatchTimeIntervalExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DispatchTimeIntervalExtensionTests.swift; sourceTree = ""; }; - 8280D7DB1C4A6EC9001172EF /* DictionaryExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryExtension.swift; sourceTree = ""; }; - 8280D7DF1C4A6FF3001172EF /* DictionaryExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryExtensionTests.swift; sourceTree = ""; }; + 827599631E520FB800787F99 /* DispatchTimeIntervalExtTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DispatchTimeIntervalExtTests.swift; sourceTree = ""; }; + 8280D7DB1C4A6EC9001172EF /* DictionaryExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryExt.swift; sourceTree = ""; }; + 8280D7DF1C4A6FF3001172EF /* DictionaryExtTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryExtTests.swift; sourceTree = ""; }; 82812A9A1D06877B00CD5B6C /* Globals.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Globals.swift; sourceTree = ""; }; 82812A9E1D06926800CD5B6C /* GlobalsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlobalsTests.swift; sourceTree = ""; }; - 82CAE2911C2ED1A200F934A7 /* StringExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = ""; }; - 82CAE2931C2ED5E000F934A7 /* StringExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensionTests.swift; sourceTree = ""; }; - 82CAE2951C2EE64900F934A7 /* ArrayExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayExtension.swift; sourceTree = ""; }; - 82CAE2971C2EE95200F934A7 /* ArrayExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayExtensionTests.swift; sourceTree = ""; }; + 82CAE2911C2ED1A200F934A7 /* StringExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExt.swift; sourceTree = ""; }; + 82CAE2931C2ED5E000F934A7 /* StringExtTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtTests.swift; sourceTree = ""; }; + 82CAE2951C2EE64900F934A7 /* ArrayExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayExt.swift; sourceTree = ""; }; + 82CAE2971C2EE95200F934A7 /* ArrayExtTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayExtTests.swift; sourceTree = ""; }; 82EB7875215B96E20042E0FD /* beak.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = beak.swift; sourceTree = ""; }; 82EB7876215B98530042E0FD /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 82F22E551C26434900E784A2 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; - A11830D21E589F6700CBE087 /* TimeIntervalExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeIntervalExtension.swift; sourceTree = ""; }; - A11830D61E58A11D00CBE087 /* TimeIntervalExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeIntervalExtensionTests.swift; sourceTree = ""; }; + A11830D21E589F6700CBE087 /* TimeIntervalExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeIntervalExt.swift; sourceTree = ""; }; + A11830D61E58A11D00CBE087 /* TimeIntervalExtTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeIntervalExtTests.swift; sourceTree = ""; }; A15C62221EE734F100A7CA38 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .swiftlint.yml; sourceTree = ""; }; A16B85EB1D8EA9A200B39055 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; A19DD6921DE2B70F00C66584 /* HandySwift.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = HandySwift.podspec; sourceTree = ""; }; - A1F221631E3CC05100419B06 /* DispatchTimeIntervalExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DispatchTimeIntervalExtension.swift; sourceTree = ""; }; + A1F221631E3CC05100419B06 /* DispatchTimeIntervalExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DispatchTimeIntervalExt.swift; sourceTree = ""; }; C5C89B9320B0A0C10048B07C /* Weak.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; C5CFB6AB20B0A70300830511 /* Unowned.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Unowned.swift; sourceTree = ""; }; CC120CC1205FDB9300C37D7C /* Regex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Regex.swift; sourceTree = ""; }; CC4AE0CD2087D895009931F6 /* RegexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegexTests.swift; sourceTree = ""; }; - CC66E046228199A0007ABF61 /* ComparableExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComparableExtension.swift; sourceTree = ""; }; - CC66E12322819FCF007ABF61 /* ComparableExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComparableExtensionTests.swift; sourceTree = ""; }; + CC66E046228199A0007ABF61 /* ComparableExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComparableExt.swift; sourceTree = ""; }; + CC66E12322819FCF007ABF61 /* ComparableExtTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComparableExtTests.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -233,8 +245,8 @@ 8203930320F3A4DF0074974F /* HandySwift */ = { isa = PBXGroup; children = ( - 82812A9A1D06877B00CD5B6C /* Globals.swift */, 823B2B4B1C24AB7F007B3CDD /* Extensions */, + 82812A9A1D06877B00CD5B6C /* Globals.swift */, 8251AA1E22786CF90022B277 /* Protocols */, 8258E4541C2E0BAF0031CBFF /* Structs */, ); @@ -278,15 +290,16 @@ 823B2B4B1C24AB7F007B3CDD /* Extensions */ = { isa = PBXGroup; children = ( - 82CAE2951C2EE64900F934A7 /* ArrayExtension.swift */, - 3F95C8D120F22A3C0045AFD0 /* CollectionExtension.swift */, - CC66E046228199A0007ABF61 /* ComparableExtension.swift */, - 8280D7DB1C4A6EC9001172EF /* DictionaryExtension.swift */, - A1F221631E3CC05100419B06 /* DispatchTimeIntervalExtension.swift */, - 823B2B4C1C24ABA4007B3CDD /* IntExtension.swift */, - 8218E4D52211D193007AAAF3 /* NSRangeExtension.swift */, - 82CAE2911C2ED1A200F934A7 /* StringExtension.swift */, - A11830D21E589F6700CBE087 /* TimeIntervalExtension.swift */, + 82CAE2951C2EE64900F934A7 /* ArrayExt.swift */, + 3F95C8D120F22A3C0045AFD0 /* CollectionExt.swift */, + CC66E046228199A0007ABF61 /* ComparableExt.swift */, + 8280D7DB1C4A6EC9001172EF /* DictionaryExt.swift */, + A1F221631E3CC05100419B06 /* DispatchTimeIntervalExt.swift */, + 823B2B4C1C24ABA4007B3CDD /* IntExt.swift */, + 2E18B291242DECCA000C7776 /* NSObjectExt.swift */, + 8218E4D52211D193007AAAF3 /* NSRangeExt.swift */, + 82CAE2911C2ED1A200F934A7 /* StringExt.swift */, + A11830D21E589F6700CBE087 /* TimeIntervalExt.swift */, ); path = Extensions; sourceTree = ""; @@ -294,15 +307,16 @@ 823B2B4E1C24ABD8007B3CDD /* Extensions */ = { isa = PBXGroup; children = ( - 82CAE2971C2EE95200F934A7 /* ArrayExtensionTests.swift */, - 3F95C8D320F22DC60045AFD0 /* CollectionExtensionTests.swift */, - CC66E12322819FCF007ABF61 /* ComparableExtensionTests.swift */, - 8280D7DF1C4A6FF3001172EF /* DictionaryExtensionTests.swift */, - 827599631E520FB800787F99 /* DispatchTimeIntervalExtensionTests.swift */, - 823B2B4F1C24AC00007B3CDD /* IntExtensionTests.swift */, - 8218E4D92211D270007AAAF3 /* NSRangeExtensionTests.swift */, - 82CAE2931C2ED5E000F934A7 /* StringExtensionTests.swift */, - A11830D61E58A11D00CBE087 /* TimeIntervalExtensionTests.swift */, + 82CAE2971C2EE95200F934A7 /* ArrayExtTests.swift */, + 3F95C8D320F22DC60045AFD0 /* CollectionExtTests.swift */, + CC66E12322819FCF007ABF61 /* ComparableExtTests.swift */, + 8280D7DF1C4A6FF3001172EF /* DictionaryExtTests.swift */, + 827599631E520FB800787F99 /* DispatchTimeIntervalExtTests.swift */, + 823B2B4F1C24AC00007B3CDD /* IntExtTests.swift */, + 2E18B295242DF436000C7776 /* NSObjectExtTests.swift */, + 8218E4D92211D270007AAAF3 /* NSRangeExtTests.swift */, + 82CAE2931C2ED5E000F934A7 /* StringExtTests.swift */, + A11830D61E58A11D00CBE087 /* TimeIntervalExtTests.swift */, ); path = Extensions; sourceTree = ""; @@ -310,6 +324,7 @@ 8251AA1E22786CF90022B277 /* Protocols */ = { isa = PBXGroup; children = ( + 63651F8F231BFF2000E022DA /* DivisibleArithmetic.swift */, 8251AA1F22786D460022B277 /* Withable.swift */, ); path = Protocols; @@ -431,11 +446,11 @@ isa = PBXNativeTarget; buildConfigurationList = 823B2B451C24AAB7007B3CDD /* Build configuration list for PBXNativeTarget "HandySwift iOS" */; buildPhases = ( + 82F967F41C67A68A0003F12A /* SwiftLint */, 823B2B2C1C24AAB6007B3CDD /* Sources */, 823B2B2D1C24AAB6007B3CDD /* Frameworks */, 823B2B2E1C24AAB6007B3CDD /* Headers */, 823B2B2F1C24AAB6007B3CDD /* Resources */, - 82F967F41C67A68A0003F12A /* SwiftLint */, ); buildRules = ( ); @@ -453,6 +468,7 @@ 823B2B371C24AAB7007B3CDD /* Sources */, 823B2B381C24AAB7007B3CDD /* Frameworks */, 823B2B391C24AAB7007B3CDD /* Resources */, + 2E78897B242B4A8100143348 /* Update LinuxMain.swift */, ); buildRules = ( ); @@ -468,11 +484,11 @@ isa = PBXNativeTarget; buildConfigurationList = 825EFDDB1C3333B000558497 /* Build configuration list for PBXNativeTarget "HandySwift macOS" */; buildPhases = ( + 82F967F51C67A69A0003F12A /* SwiftLint */, 825EFDC51C3333B000558497 /* Sources */, 825EFDC61C3333B000558497 /* Frameworks */, 825EFDC71C3333B000558497 /* Headers */, 825EFDC81C3333B000558497 /* Resources */, - 82F967F51C67A69A0003F12A /* SwiftLint */, ); buildRules = ( ); @@ -490,6 +506,7 @@ 825EFDCF1C3333B000558497 /* Sources */, 825EFDD01C3333B000558497 /* Frameworks */, 825EFDD11C3333B000558497 /* Resources */, + 2E78897C242B4B3D00143348 /* Update LinuxMain.swift */, ); buildRules = ( ); @@ -505,11 +522,11 @@ isa = PBXNativeTarget; buildConfigurationList = 825EFDFA1C33351300558497 /* Build configuration list for PBXNativeTarget "HandySwift tvOS" */; buildPhases = ( + 82F967F61C67A6A80003F12A /* SwiftLint */, 825EFDE41C33351200558497 /* Sources */, 825EFDE51C33351200558497 /* Frameworks */, 825EFDE61C33351200558497 /* Headers */, 825EFDE71C33351200558497 /* Resources */, - 82F967F61C67A6A80003F12A /* SwiftLint */, ); buildRules = ( ); @@ -527,6 +544,7 @@ 825EFDEE1C33351300558497 /* Sources */, 825EFDEF1C33351300558497 /* Frameworks */, 825EFDF01C33351300558497 /* Resources */, + 2E78897D242B4B4100143348 /* Update LinuxMain.swift */, ); buildRules = ( ); @@ -545,7 +563,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 1020; + LastUpgradeCheck = 1120; ORGANIZATIONNAME = Flinesoft; TargetAttributes = { 823B2B301C24AAB6007B3CDD = { @@ -643,6 +661,60 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 2E78897B242B4A8100143348 /* Update LinuxMain.swift */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Update LinuxMain.swift"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [ \"${CONFIGURATION}\" = \"Debug\" ]; then\n if which swiftlint > /dev/null; then\n sourcery --sources Tests --templates .sourcery/LinuxMain.stencil --output .sourcery --force-parse generated\n mv .sourcery/LinuxMain.generated.swift Tests/LinuxMain.swift\n else\n echo \"warning: Sourcery not installed, download it from https://github.com/krzysztofzablocki/Sourcery\"\n fi\nfi\n"; + }; + 2E78897C242B4B3D00143348 /* Update LinuxMain.swift */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Update LinuxMain.swift"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [ \"${CONFIGURATION}\" = \"Debug\" ]; then\n if which swiftlint > /dev/null; then\n sourcery --sources Tests --templates .sourcery/LinuxMain.stencil --output .sourcery --force-parse generated\n mv .sourcery/LinuxMain.generated.swift Tests/LinuxMain.swift\n else\n echo \"warning: Sourcery not installed, download it from https://github.com/krzysztofzablocki/Sourcery\"\n fi\nfi\n"; + }; + 2E78897D242B4B4100143348 /* Update LinuxMain.swift */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Update LinuxMain.swift"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [ \"${CONFIGURATION}\" = \"Debug\" ]; then\n if which swiftlint > /dev/null; then\n sourcery --sources Tests --templates .sourcery/LinuxMain.stencil --output .sourcery --force-parse generated\n mv .sourcery/LinuxMain.generated.swift Tests/LinuxMain.swift\n else\n echo \"warning: Sourcery not installed, download it from https://github.com/krzysztofzablocki/Sourcery\"\n fi\nfi\n"; + }; 82F967F41C67A68A0003F12A /* SwiftLint */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -695,19 +767,21 @@ 8258E4561C2E0C140031CBFF /* SortedArray.swift in Sources */, CC120CC2205FDB9300C37D7C /* Regex.swift in Sources */, 826F69AC1C3895A300B2CC6B /* FrequencyTable.swift in Sources */, - A1F221641E3CC05100419B06 /* DispatchTimeIntervalExtension.swift in Sources */, - 8218E4D62211D193007AAAF3 /* NSRangeExtension.swift in Sources */, - 3F95C8D220F22A3C0045AFD0 /* CollectionExtension.swift in Sources */, - 823B2B4D1C24ABA4007B3CDD /* IntExtension.swift in Sources */, - CC66E047228199A0007ABF61 /* ComparableExtension.swift in Sources */, + 2E18B292242DECCA000C7776 /* NSObjectExt.swift in Sources */, + A1F221641E3CC05100419B06 /* DispatchTimeIntervalExt.swift in Sources */, + 8218E4D62211D193007AAAF3 /* NSRangeExt.swift in Sources */, + 3F95C8D220F22A3C0045AFD0 /* CollectionExt.swift in Sources */, + 823B2B4D1C24ABA4007B3CDD /* IntExt.swift in Sources */, + CC66E047228199A0007ABF61 /* ComparableExt.swift in Sources */, C5C89B9420B0A0C10048B07C /* Weak.swift in Sources */, 8251AA2022786D460022B277 /* Withable.swift in Sources */, - 82CAE2921C2ED1A200F934A7 /* StringExtension.swift in Sources */, - 82CAE2961C2EE64900F934A7 /* ArrayExtension.swift in Sources */, + 82CAE2921C2ED1A200F934A7 /* StringExt.swift in Sources */, + 82CAE2961C2EE64900F934A7 /* ArrayExt.swift in Sources */, C5CFB6AC20B0A70300830511 /* Unowned.swift in Sources */, 82812A9B1D06877B00CD5B6C /* Globals.swift in Sources */, - 8280D7DC1C4A6EC9001172EF /* DictionaryExtension.swift in Sources */, - A11830D31E589F6700CBE087 /* TimeIntervalExtension.swift in Sources */, + 63651F90231BFF2000E022DA /* DivisibleArithmetic.swift in Sources */, + 8280D7DC1C4A6EC9001172EF /* DictionaryExt.swift in Sources */, + A11830D31E589F6700CBE087 /* TimeIntervalExt.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -716,18 +790,19 @@ buildActionMask = 2147483647; files = ( 826F69B01C389DB800B2CC6B /* FrequencyTableTests.swift in Sources */, - 827599641E520FB800787F99 /* DispatchTimeIntervalExtensionTests.swift in Sources */, + 827599641E520FB800787F99 /* DispatchTimeIntervalExtTests.swift in Sources */, 8258E4591C2E1ACE0031CBFF /* SortedArrayTests.swift in Sources */, - A11830D71E58A11D00CBE087 /* TimeIntervalExtensionTests.swift in Sources */, + A11830D71E58A11D00CBE087 /* TimeIntervalExtTests.swift in Sources */, 8251AA25227875C00022B277 /* WithableTests.swift in Sources */, - 823B2B501C24AC00007B3CDD /* IntExtensionTests.swift in Sources */, - 82CAE2941C2ED5E000F934A7 /* StringExtensionTests.swift in Sources */, - 82CAE2981C2EE95200F934A7 /* ArrayExtensionTests.swift in Sources */, + 823B2B501C24AC00007B3CDD /* IntExtTests.swift in Sources */, + 82CAE2941C2ED5E000F934A7 /* StringExtTests.swift in Sources */, + 82CAE2981C2EE95200F934A7 /* ArrayExtTests.swift in Sources */, 82812A9F1D06926800CD5B6C /* GlobalsTests.swift in Sources */, - 8218E4DA2211D270007AAAF3 /* NSRangeExtensionTests.swift in Sources */, - 8280D7E01C4A6FF3001172EF /* DictionaryExtensionTests.swift in Sources */, - CC66E12522819FFF007ABF61 /* ComparableExtensionTests.swift in Sources */, - 3F95C8D520F22DEE0045AFD0 /* CollectionExtensionTests.swift in Sources */, + 8218E4DA2211D270007AAAF3 /* NSRangeExtTests.swift in Sources */, + 8280D7E01C4A6FF3001172EF /* DictionaryExtTests.swift in Sources */, + CC66E12522819FFF007ABF61 /* ComparableExtTests.swift in Sources */, + 3F95C8D520F22DEE0045AFD0 /* CollectionExtTests.swift in Sources */, + 2E18B296242DF436000C7776 /* NSObjectExtTests.swift in Sources */, CC4AE0CF2087D8A7009931F6 /* RegexTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -736,22 +811,24 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 825EFE061C33358400558497 /* ArrayExtension.swift in Sources */, + 825EFE061C33358400558497 /* ArrayExt.swift in Sources */, CC120CC3205FDC4C00C37D7C /* Regex.swift in Sources */, C5CFB6AD20B0A70300830511 /* Unowned.swift in Sources */, + 2E18B293242DECCA000C7776 /* NSObjectExt.swift in Sources */, 826F69AD1C3895A300B2CC6B /* FrequencyTable.swift in Sources */, - 8218E4D72211D193007AAAF3 /* NSRangeExtension.swift in Sources */, - 825EFE051C33358400558497 /* StringExtension.swift in Sources */, - 82E21E8E211AF9960061EB1B /* CollectionExtension.swift in Sources */, - CC66E048228199DE007ABF61 /* ComparableExtension.swift in Sources */, + 8218E4D72211D193007AAAF3 /* NSRangeExt.swift in Sources */, + 825EFE051C33358400558497 /* StringExt.swift in Sources */, + 82E21E8E211AF9960061EB1B /* CollectionExt.swift in Sources */, + CC66E048228199DE007ABF61 /* ComparableExt.swift in Sources */, C5CFB6AF20B0A78F00830511 /* Weak.swift in Sources */, 8251AA2122786D460022B277 /* Withable.swift in Sources */, - A1F221651E3CC05100419B06 /* DispatchTimeIntervalExtension.swift in Sources */, + A1F221651E3CC05100419B06 /* DispatchTimeIntervalExt.swift in Sources */, 825EFE021C33358400558497 /* SortedArray.swift in Sources */, - 825EFE031C33358400558497 /* IntExtension.swift in Sources */, + 825EFE031C33358400558497 /* IntExt.swift in Sources */, 82812A9C1D06877B00CD5B6C /* Globals.swift in Sources */, - 8280D7DD1C4A6EC9001172EF /* DictionaryExtension.swift in Sources */, - A11830D41E589F6700CBE087 /* TimeIntervalExtension.swift in Sources */, + 63651F91231BFF2000E022DA /* DivisibleArithmetic.swift in Sources */, + 8280D7DD1C4A6EC9001172EF /* DictionaryExt.swift in Sources */, + A11830D41E589F6700CBE087 /* TimeIntervalExt.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -760,18 +837,19 @@ buildActionMask = 2147483647; files = ( 826F69B11C389DB800B2CC6B /* FrequencyTableTests.swift in Sources */, - 827599651E520FB800787F99 /* DispatchTimeIntervalExtensionTests.swift in Sources */, - 825EFE111C3335A400558497 /* StringExtensionTests.swift in Sources */, - A11830D81E58A11D00CBE087 /* TimeIntervalExtensionTests.swift in Sources */, + 827599651E520FB800787F99 /* DispatchTimeIntervalExtTests.swift in Sources */, + 825EFE111C3335A400558497 /* StringExtTests.swift in Sources */, + A11830D81E58A11D00CBE087 /* TimeIntervalExtTests.swift in Sources */, 8251AA26227875C00022B277 /* WithableTests.swift in Sources */, 825EFE0E1C3335A400558497 /* SortedArrayTests.swift in Sources */, - 825EFE121C3335A400558497 /* ArrayExtensionTests.swift in Sources */, - 825EFE0F1C3335A400558497 /* IntExtensionTests.swift in Sources */, + 825EFE121C3335A400558497 /* ArrayExtTests.swift in Sources */, + 825EFE0F1C3335A400558497 /* IntExtTests.swift in Sources */, 82812AA01D06926800CD5B6C /* GlobalsTests.swift in Sources */, - 8218E4DB2211D270007AAAF3 /* NSRangeExtensionTests.swift in Sources */, - 8280D7E11C4A6FF3001172EF /* DictionaryExtensionTests.swift in Sources */, - CC66E1262281A000007ABF61 /* ComparableExtensionTests.swift in Sources */, - 3F95C8D620F22DEF0045AFD0 /* CollectionExtensionTests.swift in Sources */, + 8218E4DB2211D270007AAAF3 /* NSRangeExtTests.swift in Sources */, + 8280D7E11C4A6FF3001172EF /* DictionaryExtTests.swift in Sources */, + CC66E1262281A000007ABF61 /* ComparableExtTests.swift in Sources */, + 3F95C8D620F22DEF0045AFD0 /* CollectionExtTests.swift in Sources */, + 2E18B297242DF436000C7776 /* NSObjectExtTests.swift in Sources */, CC4AE0D02087D8A8009931F6 /* RegexTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -780,22 +858,24 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 825EFE0C1C33358500558497 /* ArrayExtension.swift in Sources */, + 825EFE0C1C33358500558497 /* ArrayExt.swift in Sources */, CC120CC4205FDC4D00C37D7C /* Regex.swift in Sources */, C5CFB6AE20B0A70300830511 /* Unowned.swift in Sources */, + 2E18B294242DECCA000C7776 /* NSObjectExt.swift in Sources */, 826F69AE1C3895A300B2CC6B /* FrequencyTable.swift in Sources */, - 8218E4D82211D193007AAAF3 /* NSRangeExtension.swift in Sources */, - 825EFE0B1C33358500558497 /* StringExtension.swift in Sources */, - 82E21E8F211AF9970061EB1B /* CollectionExtension.swift in Sources */, - CC66E049228199DF007ABF61 /* ComparableExtension.swift in Sources */, + 8218E4D82211D193007AAAF3 /* NSRangeExt.swift in Sources */, + 825EFE0B1C33358500558497 /* StringExt.swift in Sources */, + 82E21E8F211AF9970061EB1B /* CollectionExt.swift in Sources */, + CC66E049228199DF007ABF61 /* ComparableExt.swift in Sources */, C5CFB6B020B0A79000830511 /* Weak.swift in Sources */, 8251AA2222786D460022B277 /* Withable.swift in Sources */, - A1F221661E3CC05100419B06 /* DispatchTimeIntervalExtension.swift in Sources */, + A1F221661E3CC05100419B06 /* DispatchTimeIntervalExt.swift in Sources */, 825EFE081C33358500558497 /* SortedArray.swift in Sources */, - 825EFE091C33358500558497 /* IntExtension.swift in Sources */, + 825EFE091C33358500558497 /* IntExt.swift in Sources */, 82812A9D1D06877B00CD5B6C /* Globals.swift in Sources */, - 8280D7DE1C4A6EC9001172EF /* DictionaryExtension.swift in Sources */, - A11830D51E589F6700CBE087 /* TimeIntervalExtension.swift in Sources */, + 63651F92231BFF2800E022DA /* DivisibleArithmetic.swift in Sources */, + 8280D7DE1C4A6EC9001172EF /* DictionaryExt.swift in Sources */, + A11830D51E589F6700CBE087 /* TimeIntervalExt.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -804,18 +884,19 @@ buildActionMask = 2147483647; files = ( 826F69B21C389DB800B2CC6B /* FrequencyTableTests.swift in Sources */, - 827599661E520FB800787F99 /* DispatchTimeIntervalExtensionTests.swift in Sources */, - 825EFE171C3335A500558497 /* StringExtensionTests.swift in Sources */, - A11830D91E58A11D00CBE087 /* TimeIntervalExtensionTests.swift in Sources */, + 827599661E520FB800787F99 /* DispatchTimeIntervalExtTests.swift in Sources */, + 825EFE171C3335A500558497 /* StringExtTests.swift in Sources */, + A11830D91E58A11D00CBE087 /* TimeIntervalExtTests.swift in Sources */, 8251AA27227875C00022B277 /* WithableTests.swift in Sources */, 825EFE141C3335A500558497 /* SortedArrayTests.swift in Sources */, - 825EFE181C3335A500558497 /* ArrayExtensionTests.swift in Sources */, - 825EFE151C3335A500558497 /* IntExtensionTests.swift in Sources */, + 825EFE181C3335A500558497 /* ArrayExtTests.swift in Sources */, + 825EFE151C3335A500558497 /* IntExtTests.swift in Sources */, 82812AA11D06926800CD5B6C /* GlobalsTests.swift in Sources */, - 8218E4DC2211D270007AAAF3 /* NSRangeExtensionTests.swift in Sources */, - 8280D7E21C4A6FF3001172EF /* DictionaryExtensionTests.swift in Sources */, - CC66E1272281A000007ABF61 /* ComparableExtensionTests.swift in Sources */, - 3F95C8D720F22DEF0045AFD0 /* CollectionExtensionTests.swift in Sources */, + 8218E4DC2211D270007AAAF3 /* NSRangeExtTests.swift in Sources */, + 8280D7E21C4A6FF3001172EF /* DictionaryExtTests.swift in Sources */, + CC66E1272281A000007ABF61 /* ComparableExtTests.swift in Sources */, + 3F95C8D720F22DEF0045AFD0 /* CollectionExtTests.swift in Sources */, + 2E18B298242DF436000C7776 /* NSObjectExtTests.swift in Sources */, CC4AE0D12087D8A9009931F6 /* RegexTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -964,7 +1045,7 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -986,7 +1067,7 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1005,6 +1086,7 @@ 823B2B491C24AAB7007B3CDD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; INFOPLIST_FILE = Tests/SupportingFiles/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.flinesoft.HandySwift-iOS-Tests"; @@ -1016,6 +1098,7 @@ 823B2B4A1C24AAB7007B3CDD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; INFOPLIST_FILE = Tests/SupportingFiles/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.flinesoft.HandySwift-iOS-Tests"; diff --git a/HandySwift.xcodeproj/xcshareddata/xcschemes/HandySwift iOS.xcscheme b/HandySwift.xcodeproj/xcshareddata/xcschemes/HandySwift iOS.xcscheme index 34be75d..a69acc5 100644 --- a/HandySwift.xcodeproj/xcshareddata/xcschemes/HandySwift iOS.xcscheme +++ b/HandySwift.xcodeproj/xcshareddata/xcschemes/HandySwift iOS.xcscheme @@ -1,6 +1,6 @@ + + + + @@ -39,17 +48,6 @@ - - - - - - - - + + + + @@ -39,17 +48,6 @@ - - - - - - - - + + + + @@ -39,17 +48,6 @@ - - - - - - - - -

- Build Status - - Codebeat Status + + Code Quality + + + Coverage - Version: 3.1.0 + Version: 3.2.0 - Swift: 5.0 + Swift: 5.1 Platforms: iOS | tvOS | macOS | Linux - + License: MIT +
+ + PayPal: Donate + + + GitHub: Become a sponsor + + + Patreon: Become a patron +

InstallationUsage + • DonationIssuesContributingLicense @@ -45,7 +62,7 @@ If you like this, please also checkout [HandyUIKit](https://github.com/Flinesoft ## Installation -Currently the recommended way of installing this library is via [Carthage](https://github.com/Carthage/Carthage) on macOS or [Swift Package Manager](https://github.com/apple/swift-package-manager) on Linux. [Cocoapods](https://github.com/CocoaPods/CocoaPods) might work, too, but is not tested. +Currently the recommended way of installing this library is via [Swift Package Manager](https://github.com/apple/swift-package-manager). [Carthage](https://github.com/Carthage/Carthage) & [Cocoapods](https://github.com/CocoaPods/CocoaPods) are supported, too. You can of course also just include this framework manually into your project by downloading it or by using git submodules. @@ -552,7 +569,7 @@ NOTE: Only available for `Int` and `Double` collections. ``` ### Withable -Simple protocol to make constructing and modifying objects with multiple properties more pleasant (functional, chainable, point-free). +Simple protocol to make constructing and modifying objects with multiple properties more pleasant (functional, chainable, point-free). Supported by all `NSObject` subclasses by default. ``` swift struct Foo: Withable { @@ -571,9 +588,16 @@ foo2.bar // => 7 ``` +## Donation + +BartyCrouch was brought to you by [Cihat Gündüz](https://github.com/Jeehut) in his free time. If you want to thank me and support the development of this project, please **make a small donation on [PayPal](https://paypal.me/Dschee/5EUR)**. In case you also like my other [open source contributions](https://github.com/Flinesoft) and [articles](https://medium.com/@Jeehut), please consider motivating me by **becoming a sponsor on [GitHub](https://github.com/sponsors/Jeehut)** or a **patron on [Patreon](https://www.patreon.com/Jeehut)**. + +Thank you very much for any donation, it really helps out a lot! 💯 + + ## Contributing -See the file [CONTRIBUTING.md](https://github.com/Flinesoft/HandySwift/blob/stable/CONTRIBUTING.md). +Contributions are welcome. Feel free to open an issue on GitHub with your ideas or implement an idea yourself and post a pull request. If you want to contribute code, please try to follow the same syntax and semantic in your **commit messages** (see rationale [here](http://chris.beams.io/posts/git-commit/)). Also, please make sure to add an entry to the `CHANGELOG.md` file which explains your change. ## License diff --git a/Sources/HandySwift/Extensions/ArrayExtension.swift b/Sources/HandySwift/Extensions/ArrayExt.swift similarity index 95% rename from Sources/HandySwift/Extensions/ArrayExtension.swift rename to Sources/HandySwift/Extensions/ArrayExt.swift index cd71986..f915e1a 100644 --- a/Sources/HandySwift/Extensions/ArrayExtension.swift +++ b/Sources/HandySwift/Extensions/ArrayExt.swift @@ -13,6 +13,7 @@ extension Array { /// - Parameters: /// - other: Other array to combine the elements with. /// - Returns: An array of tuples with the elements of both arrays combined. + @inlinable public func combinations(with other: [T]) -> [Combination] { var combinations = [(Element, T)]() forEach { elem in other.forEach { otherElem in combinations.append((elem, otherElem)) } } @@ -27,6 +28,7 @@ extension Array { /// - Parameters: /// - stable: Speifies if the sorting algorithm should be stable. /// - areInIncreasingOrder: The closure to specify the order of the elements to be sorted by. + @inlinable public mutating func sort(by areInIncreasingOrder: @escaping (Element, Element) -> Bool, stable: Bool) { guard stable else { sort(by: areInIncreasingOrder); return } stableMergeSort(by: areInIncreasingOrder) @@ -39,6 +41,7 @@ extension Array { /// - Parameters: /// - stable: Speifies if the sorting algorithm should be stable. /// - areInIncreasingOrder: The closure to specify the order of the elements to be sorted by. + @inlinable public func sorted(by areInIncreasingOrder: @escaping (Element, Element) -> Bool, stable: Bool) -> [Element] { guard stable else { return sorted(by: areInIncreasingOrder) } @@ -49,6 +52,7 @@ extension Array { } /// Sorts the array in-place using a stable merge sort algorithm. + @inlinable mutating func stableMergeSort(by areInIncreasingOrder: @escaping (Element, Element) -> Bool) { var tmp = [Element]() tmp.reserveCapacity(numericCast(count)) @@ -91,7 +95,7 @@ extension RandomAccessCollection where Index == Int { /// Returns a random element from the `Array`. /// /// - Returns: A random element from the array or `nil` if empty. - public var sample: Element? { + @inlinable public var sample: Element? { guard let randomIndex = Int(randomBelow: count) else { return nil } return self[randomIndex] } @@ -101,6 +105,7 @@ extension RandomAccessCollection where Index == Int { /// - Parameters: /// - size: The number of random elements wanted. /// - Returns: An array with the given number of random elements or `nil` if empty. + @inlinable public func sample(size: Int) -> [Element]? { guard !isEmpty else { return nil } @@ -118,6 +123,7 @@ extension Array where Element: Comparable { /// /// - Parameters: /// - stable: Speifies if the sorting algorithm should be stable. + @inlinable public mutating func sort(stable: Bool) { sort(by: { lhs, rhs in lhs < rhs }, stable: stable) } @@ -128,7 +134,8 @@ extension Array where Element: Comparable { /// /// - Parameters: /// - stable: Speifies if the sorting algorithm should be stable. + @inlinable public func sorted(stable: Bool) -> [Element] { - return sorted(by: { lhs, rhs in lhs < rhs }, stable: stable) + sorted(by: { lhs, rhs in lhs < rhs }, stable: stable) } } diff --git a/Sources/HandySwift/Extensions/CollectionExtension.swift b/Sources/HandySwift/Extensions/CollectionExt.swift similarity index 57% rename from Sources/HandySwift/Extensions/CollectionExtension.swift rename to Sources/HandySwift/Extensions/CollectionExt.swift index 4c33a27..e4eb719 100644 --- a/Sources/HandySwift/Extensions/CollectionExtension.swift +++ b/Sources/HandySwift/Extensions/CollectionExt.swift @@ -7,28 +7,32 @@ extension Collection { /// /// - Parameters: /// - try: The index of the element. + @inlinable public subscript(try index: Index) -> Element? { - return indices.contains(index) ? self[index] : nil + indices.contains(index) ? self[index] : nil } } extension Sequence where Element: Numeric { /// Returns the sum of all elements. + @inlinable public func sum() -> Element { - return reduce(0, +) + reduce(0, +) } } -extension Collection where Element == Int { - /// Returns the average of all elements as a Double value. - public func average() -> Double { - return reduce(0) { $0 + Double($1) } / Double(count) +extension Collection where Element: DivisibleArithmetic { + /// Returns the average of all elements. + @inlinable + public func average() -> Element { + sum() / Element(count) } } -extension Collection where Element == Double { +extension Collection where Element == Int { /// Returns the average of all elements as a Double value. - public func average() -> Double { - return reduce(0, +) / Double(count) + @inlinable + public func average() -> ReturnType { + ReturnType(sum()) / ReturnType(count) } } diff --git a/Sources/HandySwift/Extensions/ComparableExtension.swift b/Sources/HandySwift/Extensions/ComparableExt.swift similarity index 97% rename from Sources/HandySwift/Extensions/ComparableExtension.swift rename to Sources/HandySwift/Extensions/ComparableExt.swift index 164351a..a71656f 100644 --- a/Sources/HandySwift/Extensions/ComparableExtension.swift +++ b/Sources/HandySwift/Extensions/ComparableExt.swift @@ -11,6 +11,7 @@ extension Comparable { /// - `self`, if it is inside the given limits. /// - `lowerBound` of the given limits, if `self` is smaller than it. /// - `upperBound` of the given limits, if `self` is greater than it. + @inlinable public func clamped(to limits: ClosedRange) -> Self { if limits.lowerBound > self { return limits.lowerBound @@ -27,6 +28,7 @@ extension Comparable { /// - Returns: /// - `self`, if it is inside the given limits. /// - `lowerBound` of the given limits, if `self` is smaller than it. + @inlinable public func clamped(to limits: PartialRangeFrom) -> Self { if limits.lowerBound > self { return limits.lowerBound @@ -41,6 +43,7 @@ extension Comparable { /// - Returns: /// - `self`, if it is inside the given limits. /// - `upperBound` of the given limits, if `self` is greater than it. + @inlinable public func clamped(to limits: PartialRangeThrough) -> Self { if limits.upperBound < self { return limits.upperBound @@ -57,6 +60,7 @@ extension Comparable { /// - `upperBound` of the given limits, if `self` is greater than it. /// /// - Parameter limits: The closed range determining minimum & maxmimum value. + @inlinable public mutating func clamp(to limits: ClosedRange) { self = clamped(to: limits) } @@ -67,6 +71,7 @@ extension Comparable { /// - `lowerBound` of the given limits, if `self` is smaller than it. /// /// - Parameter limits: The partial range (from) determining the minimum value. + @inlinable public mutating func clamp(to limits: PartialRangeFrom) { self = clamped(to: limits) } @@ -77,6 +82,7 @@ extension Comparable { /// - `upperBound` of the given limits, if `self` is greater than it. /// /// - Parameter limits: The partial range (through) determining the maximum value. + @inlinable public mutating func clamp(to limits: PartialRangeThrough) { self = clamped(to: limits) } diff --git a/Sources/HandySwift/Extensions/DictionaryExtension.swift b/Sources/HandySwift/Extensions/DictionaryExt.swift similarity index 97% rename from Sources/HandySwift/Extensions/DictionaryExtension.swift rename to Sources/HandySwift/Extensions/DictionaryExt.swift index 6ac9565..0608f15 100644 --- a/Sources/HandySwift/Extensions/DictionaryExtension.swift +++ b/Sources/HandySwift/Extensions/DictionaryExt.swift @@ -8,6 +8,7 @@ extension Dictionary { /// - Parameters: /// - keys: The `Array` of keys. /// - values: The `Array` of values. + @inlinable public init?(keys: [Key], values: [Value]) { guard keys.count == values.count else { return nil } self.init() @@ -18,6 +19,7 @@ extension Dictionary { /// /// - Parameters: /// - otherDictionary: The other `Dictionary` to merge into this `Dictionary`. + @inlinable public mutating func merge(_ other: [Key: Value]) { for (key, value) in other { self[key] = value } } @@ -28,6 +30,7 @@ extension Dictionary { /// - Parameters: /// - otherDictionary: The other `Dictionary` to merge into this `Dictionary`. /// - Returns: The new Dictionary with merged keys and values from this and the other `Dictionary`. + @inlinable public func merged(with other: [Key: Value]) -> [Key: Value] { var newDict: [Key: Value] = [:] [self, other].forEach { dict in for (key, value) in dict { newDict[key] = value } } diff --git a/Sources/HandySwift/Extensions/DispatchTimeIntervalExtension.swift b/Sources/HandySwift/Extensions/DispatchTimeIntervalExt.swift similarity index 100% rename from Sources/HandySwift/Extensions/DispatchTimeIntervalExtension.swift rename to Sources/HandySwift/Extensions/DispatchTimeIntervalExt.swift diff --git a/Sources/HandySwift/Extensions/IntExtension.swift b/Sources/HandySwift/Extensions/IntExt.swift similarity index 63% rename from Sources/HandySwift/Extensions/IntExtension.swift rename to Sources/HandySwift/Extensions/IntExt.swift index 65fe6c5..7d74eb6 100644 --- a/Sources/HandySwift/Extensions/IntExtension.swift +++ b/Sources/HandySwift/Extensions/IntExt.swift @@ -12,10 +12,21 @@ extension Int { self = .random(in: 0 ..< upperLimit) } + /// Initializes a new `Int ` instance with a random value below a given `Int`. + /// + /// - Parameters: + /// - randomBelow: The upper bound value to create a random value with. + /// - generator: The `RandomNumberGenerator` source that should be used to generate random numbers. + public init?(randomBelow upperLimit: Int, using generator: inout Generator) { + guard upperLimit > 0 else { return nil } + self = .random(in: 0 ..< upperLimit, using: &generator) + } + /// Runs the code passed as a closure the specified number of times. /// /// - Parameters: /// - closure: The code to be run multiple times. + @inlinable public func times(_ closure: () -> Void) { guard self > 0 else { return } for _ in 0 ..< self { closure() } @@ -26,8 +37,9 @@ extension Int { /// /// - Parameters: /// - closure: The code to deliver a return value multiple times. + @inlinable public func timesMake(_ closure: () -> ReturnType) -> [ReturnType] { guard self > 0 else { return [] } - return (0 ..< self).map { _ in return closure() } + return (0 ..< self).map { _ in closure() } } } diff --git a/Sources/HandySwift/Extensions/NSObjectExt.swift b/Sources/HandySwift/Extensions/NSObjectExt.swift new file mode 100644 index 0000000..f7ecf51 --- /dev/null +++ b/Sources/HandySwift/Extensions/NSObjectExt.swift @@ -0,0 +1,7 @@ +// Copyright © 2020 Flinesoft. All rights reserved. + +import Foundation + +#if !os(Linux) + extension NSObject: Withable {} +#endif diff --git a/Sources/HandySwift/Extensions/NSRangeExtension.swift b/Sources/HandySwift/Extensions/NSRangeExt.swift similarity index 100% rename from Sources/HandySwift/Extensions/NSRangeExtension.swift rename to Sources/HandySwift/Extensions/NSRangeExt.swift diff --git a/Sources/HandySwift/Extensions/StringExtension.swift b/Sources/HandySwift/Extensions/StringExt.swift similarity index 88% rename from Sources/HandySwift/Extensions/StringExtension.swift rename to Sources/HandySwift/Extensions/StringExt.swift index 8b81c3a..1aacb9a 100644 --- a/Sources/HandySwift/Extensions/StringExtension.swift +++ b/Sources/HandySwift/Extensions/StringExt.swift @@ -4,23 +4,23 @@ import Foundation extension String { /// - Returns: `true` if contains any cahracters other than whitespace or newline characters, else `no`. - public var isBlank: Bool { return stripped().isEmpty } + public var isBlank: Bool { stripped().isEmpty } /// Returns a random character from the String. /// /// - Returns: A random character from the String or `nil` if empty. public var sample: Character? { - return isEmpty ? nil : self[index(startIndex, offsetBy: Int(randomBelow: count)!)] + isEmpty ? nil : self[index(startIndex, offsetBy: Int(randomBelow: count)!)] } /// Returns the range containing the full String. public var fullRange: Range { - return startIndex ..< endIndex + startIndex ..< endIndex } /// Returns the range as NSRange type for the full String. public var fullNSRange: NSRange { - return NSRange(fullRange, in: self) + NSRange(fullRange, in: self) } /// Create new instance with random numeric/alphabetic/alphanumeric String of given length. @@ -49,13 +49,14 @@ extension String { } /// - Returns: The string stripped by whitespace and newline characters from beginning and end. - public func stripped() -> String { return trimmingCharacters(in: .whitespacesAndNewlines) } + public func stripped() -> String { trimmingCharacters(in: .whitespacesAndNewlines) } /// Returns a given number of random characters from the String. /// /// - Parameters: /// - size: The number of random characters wanted. /// - Returns: A String with the given number of random characters or `nil` if empty. + @inlinable public func sample(size: Int) -> String? { guard !isEmpty else { return nil } diff --git a/Sources/HandySwift/Extensions/TimeIntervalExtension.swift b/Sources/HandySwift/Extensions/TimeIntervalExt.swift similarity index 55% rename from Sources/HandySwift/Extensions/TimeIntervalExtension.swift rename to Sources/HandySwift/Extensions/TimeIntervalExt.swift index 229bd70..0bc14bf 100644 --- a/Sources/HandySwift/Extensions/TimeIntervalExtension.swift +++ b/Sources/HandySwift/Extensions/TimeIntervalExt.swift @@ -7,82 +7,89 @@ public typealias Timespan = TimeInterval extension TimeInterval { // MARK: - Computed Type Properties - internal static var secondsPerDay: Double { return 24 * 60 * 60 } - internal static var secondsPerHour: Double { return 60 * 60 } - internal static var secondsPerMinute: Double { return 60 } - internal static var millisecondsPerSecond: Double { return 1_000 } - internal static var microsecondsPerSecond: Double { return 1_000 * 1_000 } - internal static var nanosecondsPerSecond: Double { return 1_000 * 1_000 * 1_000 } + @usableFromInline internal static var secondsPerDay: Double { 24 * 60 * 60 } + @usableFromInline internal static var secondsPerHour: Double { 60 * 60 } + @usableFromInline internal static var secondsPerMinute: Double { 60 } + @usableFromInline internal static var millisecondsPerSecond: Double { 1_000 } + @usableFromInline internal static var microsecondsPerSecond: Double { 1_000 * 1_000 } + @usableFromInline internal static var nanosecondsPerSecond: Double { 1_000 * 1_000 * 1_000 } // MARK: - Computed Instance Properties /// - Returns: The `TimeInterval` in days. - public var days: Double { - return self / TimeInterval.secondsPerDay + @inlinable public var days: Double { + self / TimeInterval.secondsPerDay } /// - Returns: The `TimeInterval` in hours. - public var hours: Double { - return self / TimeInterval.secondsPerHour + @inlinable public var hours: Double { + self / TimeInterval.secondsPerHour } /// - Returns: The `TimeInterval` in minutes. - public var minutes: Double { - return self / TimeInterval.secondsPerMinute + @inlinable public var minutes: Double { + self / TimeInterval.secondsPerMinute } /// - Returns: The `TimeInterval` in seconds. - public var seconds: Double { - return self + @inlinable public var seconds: Double { + self } /// - Returns: The `TimeInterval` in milliseconds. - public var milliseconds: Double { - return self * TimeInterval.millisecondsPerSecond + @inlinable public var milliseconds: Double { + self * TimeInterval.millisecondsPerSecond } /// - Returns: The `TimeInterval` in microseconds. - public var microseconds: Double { - return self * TimeInterval.microsecondsPerSecond + @inlinable public var microseconds: Double { + self * TimeInterval.microsecondsPerSecond } /// - Returns: The `TimeInterval` in nanoseconds. - public var nanoseconds: Double { - return self * TimeInterval.nanosecondsPerSecond + @inlinable public var nanoseconds: Double { + self * TimeInterval.nanosecondsPerSecond } // MARK: - Type Methods /// - Returns: The time in days using the `TimeInterval` type. + @inlinable public static func days(_ value: Double) -> TimeInterval { - return value * secondsPerDay + value * secondsPerDay } /// - Returns: The time in hours using the `TimeInterval` type. + @inlinable public static func hours(_ value: Double) -> TimeInterval { - return value * secondsPerHour + value * secondsPerHour } /// - Returns: The time in minutes using the `TimeInterval` type. + @inlinable public static func minutes(_ value: Double) -> TimeInterval { - return value * secondsPerMinute + value * secondsPerMinute } /// - Returns: The time in seconds using the `TimeInterval` type. + @inlinable public static func seconds(_ value: Double) -> TimeInterval { - return value + value } /// - Returns: The time in milliseconds using the `TimeInterval` type. + @inlinable public static func milliseconds(_ value: Double) -> TimeInterval { - return value / millisecondsPerSecond + value / millisecondsPerSecond } /// - Returns: The time in microseconds using the `TimeInterval` type. + @inlinable public static func microseconds(_ value: Double) -> TimeInterval { - return value / microsecondsPerSecond + value / microsecondsPerSecond } /// - Returns: The time in nanoseconds using the `TimeInterval` type. + @inlinable public static func nanoseconds(_ value: Double) -> TimeInterval { - return value / nanosecondsPerSecond + value / nanosecondsPerSecond } } diff --git a/Sources/HandySwift/Protocols/DivisibleArithmetic.swift b/Sources/HandySwift/Protocols/DivisibleArithmetic.swift new file mode 100644 index 0000000..5e54c6f --- /dev/null +++ b/Sources/HandySwift/Protocols/DivisibleArithmetic.swift @@ -0,0 +1,16 @@ +// Copyright © 2019 Flinesoft. All rights reserved. + +/// A type which conforms to DivisibleArithmetic provides the basic arithmetic operations: additon, subtraction, multiplication and division. +public protocol DivisibleArithmetic: Numeric { + init(_ value: Int) + static func / (lhs: Self, rhs: Self) -> Self +} + +extension Double: DivisibleArithmetic {} +extension Float: DivisibleArithmetic {} + +#if canImport(CoreGraphics) + import CoreGraphics + + extension CGFloat: DivisibleArithmetic {} +#endif diff --git a/Sources/HandySwift/Protocols/Withable.swift b/Sources/HandySwift/Protocols/Withable.swift index 89828ed..9530281 100644 --- a/Sources/HandySwift/Protocols/Withable.swift +++ b/Sources/HandySwift/Protocols/Withable.swift @@ -8,12 +8,14 @@ public protocol Withable { extension Withable { /// Construct a new instance, setting an arbitrary subset of properties. + @inlinable public init(with config: (inout Self) -> Void) { self.init() config(&self) } /// Create a copy, overriding an arbitrary subset of properties. + @inlinable public func with(_ config: (inout Self) -> Void) -> Self { var copy = self config(©) diff --git a/Sources/HandySwift/Structs/FrequencyTable.swift b/Sources/HandySwift/Structs/FrequencyTable.swift index cdee255..45cb90b 100644 --- a/Sources/HandySwift/Structs/FrequencyTable.swift +++ b/Sources/HandySwift/Structs/FrequencyTable.swift @@ -5,17 +5,18 @@ import Foundation /// Data structure to retrieve random values with their frequency taken into account. public struct FrequencyTable { // MARK: - Sub Types + @usableFromInline typealias Entry = (value: T, frequency: Int) // MARK: - Stored Instance Properties - private let valuesWithFrequencies: [Entry] + @usableFromInline internal let valuesWithFrequencies: [Entry] /// Contains all values the amount of time of their frequencies. - private let frequentValues: [T] + @usableFromInline internal let frequentValues: [T] // MARK: - Computed Instance Properties /// - Returns: A random value taking frequencies into account or nil if values empty. - public var sample: T? { return frequentValues.sample } + @inlinable public var sample: T? { frequentValues.sample } // MARK: - Initializers /// Creates a new FrequencyTable instance with values and their frequencies provided. @@ -23,10 +24,11 @@ public struct FrequencyTable { /// - Parameters: /// - values: An array full of values to be saved into the frequency table. /// - frequencyClosure: The closure to specify the frequency for a specific value. + @inlinable public init(values: [T], frequencyClosure: (T) -> Int) { valuesWithFrequencies = values.map { ($0, frequencyClosure($0)) } - frequentValues = valuesWithFrequencies.reduce([]) { memo, entry in - return memo + Array(repeating: entry.value, count: entry.frequency) + frequentValues = valuesWithFrequencies.reduce(into: []) { memo, entry in + memo += Array(repeating: entry.value, count: entry.frequency) } } @@ -37,6 +39,7 @@ public struct FrequencyTable { /// - size: The size of the resulting array of random values. /// /// - Returns: An array of random values or nil if values empty. + @inlinable public func sample(size: Int) -> [T]? { guard size > 0 && !frequentValues.isEmpty else { return nil } return Array(0 ..< size).map { _ in sample! } diff --git a/Sources/HandySwift/Structs/Regex.swift b/Sources/HandySwift/Structs/Regex.swift index 234c5e7..c62d00a 100644 --- a/Sources/HandySwift/Structs/Regex.swift +++ b/Sources/HandySwift/Structs/Regex.swift @@ -6,7 +6,7 @@ import Foundation /// `Regex` is a swifty regex engine built on top of the NSRegularExpression api. public struct Regex { // MARK: - Properties - private let regularExpression: NSRegularExpression + @usableFromInline internal let regularExpression: NSRegularExpression // MARK: - Initializers /// Create a `Regex` based on a pattern string. @@ -33,8 +33,9 @@ public struct Regex { /// - parameter string: The string to test. /// /// - returns: `true` if the regular expression matches, otherwise `false`. + @inlinable public func matches(_ string: String) -> Bool { - return firstMatch(in: string) != nil + firstMatch(in: string) != nil } /// If the regex matches `string`, returns a `Match` describing the @@ -44,6 +45,7 @@ public struct Regex { /// - parameter string: The string to match against. /// /// - returns: An optional `Match` describing the first match, or `nil`. + @inlinable public func firstMatch(in string: String) -> Match? { let firstMatch = regularExpression .firstMatch(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count)) @@ -58,6 +60,7 @@ public struct Regex { /// - parameter string: The string to match against. /// /// - returns: An array of `Match` describing every match in `string`. + @inlinable public func matches(in string: String) -> [Match] { let matches = regularExpression .matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count)) @@ -82,6 +85,7 @@ public struct Regex { /// - count: The maximum count of matches to replace, beginning with the first match. /// /// - returns: A string with all matches of `regex` replaced by `template`. + @inlinable public func replacingMatches(in input: String, with template: String, count: Int? = nil) -> String { var output = input let matches = self.matches(in: input) @@ -99,7 +103,7 @@ public struct Regex { extension Regex: CustomStringConvertible { /// Returns a string describing the regex using its pattern string. public var description: String { - return "Regex<\"\(regularExpression.pattern)\">" + "Regex<\"\(regularExpression.pattern)\">" } } @@ -109,7 +113,7 @@ extension Regex: Equatable { /// Two `Regex` are considered equal, if both the pattern string and the options /// passed on initialization are equal. public static func == (lhs: Regex, rhs: Regex) -> Bool { - return lhs.regularExpression.pattern == rhs.regularExpression.pattern && + lhs.regularExpression.pattern == rhs.regularExpression.pattern && lhs.regularExpression.options == rhs.regularExpression.options } } @@ -175,12 +179,12 @@ extension Regex { // MARK: Properties /// The entire matched string. public lazy var string: String = { - return String(describing: self.baseString[self.range]) + String(describing: self.baseString[self.range]) }() /// The range of the matched string. public lazy var range: Range = { - return Range(self.result.range, in: self.baseString)! + Range(self.result.range, in: self.baseString)! }() /// The matching string for each capture group in the regular expression @@ -219,6 +223,7 @@ extension Regex { private let baseString: String // MARK: - Initializers + @usableFromInline internal init(result: NSTextCheckingResult, in string: String) { precondition( result.regularExpression != nil, @@ -257,7 +262,7 @@ extension Regex { // MARK: - CustomStringConvertible /// Returns a string describing the match. public var description: String { - return "Match<\"\(string)\">" + "Match<\"\(string)\">" } } } diff --git a/Sources/HandySwift/Structs/SortedArray.swift b/Sources/HandySwift/Structs/SortedArray.swift index 07d50e1..66a41f9 100644 --- a/Sources/HandySwift/Structs/SortedArray.swift +++ b/Sources/HandySwift/Structs/SortedArray.swift @@ -5,10 +5,10 @@ import Foundation /// Data structure to keep a sorted array of elements for fast access. public struct SortedArray { // MARK: - Stored Instance Properties - private var internalArray: [Element] + @usableFromInline internal var internalArray: [Element] /// Returns the sorted array of elements. - public var array: [Element] { return self.internalArray } + public var array: [Element] { self.internalArray } // MARK: - Initializers /// Creates a new, empty array. @@ -30,7 +30,8 @@ public struct SortedArray { self.init(sequence: sequence, preSorted: false) } - private init(sequence: S, preSorted: Bool) where S.Iterator.Element == Element { + @usableFromInline + internal init(sequence: S, preSorted: Bool) where S.Iterator.Element == Element { internalArray = preSorted ? Array(sequence) : Array(sequence).sorted() } @@ -43,6 +44,7 @@ public struct SortedArray { /// - Parameters: /// - predicate: The predicate to match the elements against. /// - Returns: The index of the first matching element or `nil` if none of them matches. + @inlinable public func index(where predicate: (Element) -> Bool) -> Int? { // cover trivial cases guard !array.isEmpty else { return nil } @@ -75,6 +77,7 @@ public struct SortedArray { /// - Parameters: /// - index: The upper bound index until which to include elements. /// - Returns: A new SortedArray instance including all elements until the specified index (exluding it). + @inlinable public func prefix(upTo index: Int) -> SortedArray { let subarray = Array(array[array.indices.prefix(upTo: index)]) return SortedArray(sequence: subarray, preSorted: true) @@ -87,6 +90,7 @@ public struct SortedArray { /// - Parameters: /// - index: The upper bound index until which to include elements. /// - Returns: A new SortedArray instance including all elements until the specified index (including it). + @inlinable public func prefix(through index: Int) -> SortedArray { let subarray = Array(array[array.indices.prefix(through: index)]) return SortedArray(sequence: subarray, preSorted: true) @@ -99,6 +103,7 @@ public struct SortedArray { /// - Parameters: /// - index: The lower bound index from which to start including elements. /// - Returns: A new SortedArray instance including all elements starting at the specified index. + @inlinable public func suffix(from index: Int) -> SortedArray { let subarray = Array(array[array.indices.suffix(from: index)]) return SortedArray(sequence: subarray, preSorted: true) @@ -111,6 +116,7 @@ public struct SortedArray { /// /// - Parameters: /// - newElement: The new element to be inserted into the array. + @inlinable public mutating func insert(newElement: Element) { let insertIndex = internalArray.firstIndex { $0 >= newElement } ?? internalArray.endIndex internalArray.insert(newElement, at: insertIndex) @@ -122,6 +128,7 @@ public struct SortedArray { /// /// - Parameters: /// - sequence + @inlinable public mutating func insert(contentsOf sequence: S) where S.Iterator.Element == Element { sequence.forEach { insert(newElement: $0) } } @@ -132,6 +139,7 @@ public struct SortedArray { /// /// - Parameters: /// - index: The index of the element to remove from the sorted array. + @inlinable public mutating func remove(at index: Int) { internalArray.remove(at: index) } @@ -140,32 +148,36 @@ public struct SortedArray { /// /// - Parameter /// - bounds: A range of the SortedArray's indices. The bounds of the range must be valid indices. + @inlinable public subscript(bounds: Range) -> SortedArray { - return SortedArray(sequence: array[bounds], preSorted: true) + SortedArray(sequence: array[bounds], preSorted: true) } } extension SortedArray: Collection { public typealias Index = Array.Index - public var startIndex: Int { - return internalArray.startIndex + @inlinable public var startIndex: Int { + internalArray.startIndex } - public var endIndex: Int { - return internalArray.endIndex + @inlinable public var endIndex: Int { + internalArray.endIndex } + @inlinable public func sorted() -> [Element] { - return internalArray + internalArray } + @inlinable public func index(after index: Int) -> Int { - return internalArray.index(after: index) + internalArray.index(after: index) } + @inlinable public subscript(position: Int) -> Element { - return internalArray[position] + internalArray[position] } } diff --git a/Sources/HandySwift/Structs/Unowned.swift b/Sources/HandySwift/Structs/Unowned.swift index 17275be..3d369b6 100644 --- a/Sources/HandySwift/Structs/Unowned.swift +++ b/Sources/HandySwift/Structs/Unowned.swift @@ -16,7 +16,7 @@ public struct Unowned where Wrapped: AnyObject { extension Unowned: CustomDebugStringConvertible where Wrapped: CustomDebugStringConvertible { /// A textual representation of this instance, suitable for debugging. public var debugDescription: String { - return value.debugDescription + value.debugDescription } } @@ -39,7 +39,7 @@ extension Unowned: Equatable where Wrapped: Equatable { /// - lhs: An optional value to compare. /// - rhs: Another optional value to compare. public static func == (lhs: Unowned, rhs: Unowned) -> Bool { - return lhs.value == rhs.value + lhs.value == rhs.value } } diff --git a/Sources/HandySwift/Structs/Weak.swift b/Sources/HandySwift/Structs/Weak.swift index a16f867..bc656e6 100644 --- a/Sources/HandySwift/Structs/Weak.swift +++ b/Sources/HandySwift/Structs/Weak.swift @@ -24,6 +24,7 @@ public struct Weak: ExpressibleByNilLiteral where Wrapped: AnyObject { /// of the instance. /// - Returns: The result of the given closure. If this instance is `nil`, /// returns `nil`. + @inlinable public func map(_ transform: (Wrapped) throws -> U) rethrows -> U? { guard let value = value else { return nil } @@ -37,6 +38,7 @@ public struct Weak: ExpressibleByNilLiteral where Wrapped: AnyObject { /// of the instance. /// - Returns: The result of the given closure. If this instance is `nil`, /// returns `nil`. + @inlinable public func flatMap(_ transform: (Wrapped) throws -> U?) rethrows -> U? { guard let value = value else { return nil } @@ -47,7 +49,7 @@ public struct Weak: ExpressibleByNilLiteral where Wrapped: AnyObject { extension Weak: CustomDebugStringConvertible { /// A textual representation of this instance, suitable for debugging. public var debugDescription: String { - return value.debugDescription + value.debugDescription } } @@ -70,7 +72,7 @@ extension Weak: Equatable where Wrapped: Equatable { /// - lhs: An optional value to compare. /// - rhs: Another optional value to compare. public static func == (lhs: Weak, rhs: Weak) -> Bool { - return lhs.value == rhs.value + lhs.value == rhs.value } } diff --git a/Sources/SupportingFiles/Info.plist b/Sources/SupportingFiles/Info.plist index 651d2ab..fdc4357 100644 --- a/Sources/SupportingFiles/Info.plist +++ b/Sources/SupportingFiles/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 3.1.0 + 3.2.0 CFBundleSignature ???? diff --git a/Tests/HandySwiftTests/Extensions/ArrayExtensionTests.swift b/Tests/HandySwiftTests/Extensions/ArrayExtTests.swift similarity index 96% rename from Tests/HandySwiftTests/Extensions/ArrayExtensionTests.swift rename to Tests/HandySwiftTests/Extensions/ArrayExtTests.swift index c45db26..2d5f026 100644 --- a/Tests/HandySwiftTests/Extensions/ArrayExtensionTests.swift +++ b/Tests/HandySwiftTests/Extensions/ArrayExtTests.swift @@ -3,12 +3,12 @@ @testable import HandySwift import XCTest -class ArrayExtensionTests: XCTestCase { +class ArrayExtTests: XCTestCase { struct T: Equatable { // swiftlint:disable:this type_name let a: Int, b: Int // swiftlint:disable:this identifier_name static func == (lhs: T, rhs: T) -> Bool { - return lhs.a == rhs.a && lhs.b == rhs.b + lhs.a == rhs.a && lhs.b == rhs.b } } diff --git a/Tests/HandySwiftTests/Extensions/CollectionExtensionTests.swift b/Tests/HandySwiftTests/Extensions/CollectionExtTests.swift similarity index 69% rename from Tests/HandySwiftTests/Extensions/CollectionExtensionTests.swift rename to Tests/HandySwiftTests/Extensions/CollectionExtTests.swift index 91dbf7d..5455c0a 100644 --- a/Tests/HandySwiftTests/Extensions/CollectionExtensionTests.swift +++ b/Tests/HandySwiftTests/Extensions/CollectionExtTests.swift @@ -3,7 +3,7 @@ @testable import HandySwift import XCTest -class CollectionExtensionTests: XCTestCase { +class CollectionExtTests: XCTestCase { func testTrySubscript() { let testArray = [0, 1, 2, 3, 20] @@ -28,7 +28,17 @@ class CollectionExtensionTests: XCTestCase { let intArray = [1, 2, 10] XCTAssertEqual(intArray.average(), 4.333, accuracy: 0.001) + #if canImport(CoreGraphics) + let averageAsCGFloat: CGFloat = intArray.average() + XCTAssertEqual(averageAsCGFloat, 4.333, accuracy: 0.001) + #endif + let doubleArray = [1.0, 2.0, 10.0] XCTAssertEqual(doubleArray.average(), 4.333, accuracy: 0.001) + + #if canImport(CoreGraphics) + let cgFloatArray: [CGFloat] = [1.0, 2.0, 10.0] + XCTAssertEqual(cgFloatArray.average(), 4.333, accuracy: 0.001) + #endif } } diff --git a/Tests/HandySwiftTests/Extensions/ComparableExtensionTests.swift b/Tests/HandySwiftTests/Extensions/ComparableExtTests.swift similarity index 98% rename from Tests/HandySwiftTests/Extensions/ComparableExtensionTests.swift rename to Tests/HandySwiftTests/Extensions/ComparableExtTests.swift index dd07346..53d9c05 100644 --- a/Tests/HandySwiftTests/Extensions/ComparableExtensionTests.swift +++ b/Tests/HandySwiftTests/Extensions/ComparableExtTests.swift @@ -5,7 +5,7 @@ import Foundation @testable import HandySwift import XCTest -class ComparableExtensionTests: XCTestCase { +class ComparableExtTests: XCTestCase { // MARK: Returning Variants func testClampedClosedRange() { let myNum = 3 diff --git a/Tests/HandySwiftTests/Extensions/DictionaryExtensionTests.swift b/Tests/HandySwiftTests/Extensions/DictionaryExtTests.swift similarity index 97% rename from Tests/HandySwiftTests/Extensions/DictionaryExtensionTests.swift rename to Tests/HandySwiftTests/Extensions/DictionaryExtTests.swift index 8dbb327..d4eede4 100644 --- a/Tests/HandySwiftTests/Extensions/DictionaryExtensionTests.swift +++ b/Tests/HandySwiftTests/Extensions/DictionaryExtTests.swift @@ -3,7 +3,7 @@ @testable import HandySwift import XCTest -class DictionaryExtensionTests: XCTestCase { +class DictionaryExtTests: XCTestCase { func testInitWithSameCountKeysAndValues() { let keys = Array(0 ..< 100) let values = Array(stride(from: 0, to: 10 * 100, by: 10)) diff --git a/Tests/HandySwiftTests/Extensions/DispatchTimeIntervalExtensionTests.swift b/Tests/HandySwiftTests/Extensions/DispatchTimeIntervalExtTests.swift similarity index 85% rename from Tests/HandySwiftTests/Extensions/DispatchTimeIntervalExtensionTests.swift rename to Tests/HandySwiftTests/Extensions/DispatchTimeIntervalExtTests.swift index 9471bd6..27a4392 100644 --- a/Tests/HandySwiftTests/Extensions/DispatchTimeIntervalExtensionTests.swift +++ b/Tests/HandySwiftTests/Extensions/DispatchTimeIntervalExtTests.swift @@ -3,7 +3,7 @@ @testable import HandySwift import XCTest -class DispatchTimeIntervalExtensionTests: XCTestCase { +class DispatchTimeIntervalExtTests: XCTestCase { func testTimeInterval() { let dispatchTimeInterval = DispatchTimeInterval.milliseconds(500) let timeInterval = dispatchTimeInterval.timeInterval diff --git a/Tests/HandySwiftTests/Extensions/IntExtensionTests.swift b/Tests/HandySwiftTests/Extensions/IntExtTests.swift similarity index 70% rename from Tests/HandySwiftTests/Extensions/IntExtensionTests.swift rename to Tests/HandySwiftTests/Extensions/IntExtTests.swift index f7b9ee1..6d69c42 100644 --- a/Tests/HandySwiftTests/Extensions/IntExtensionTests.swift +++ b/Tests/HandySwiftTests/Extensions/IntExtTests.swift @@ -3,7 +3,7 @@ @testable import HandySwift import XCTest -class IntExtensionTests: XCTestCase { +class IntExtTests: XCTestCase { func testInitRandomBelow() { 10.times { XCTAssertTrue(Int(randomBelow: 15)! < 15) @@ -11,6 +11,14 @@ class IntExtensionTests: XCTestCase { XCTAssertNil(Int(randomBelow: 0)) XCTAssertNil(Int(randomBelow: -1)) } + + var generator = SystemRandomNumberGenerator() + 10.times { + XCTAssertTrue(Int(randomBelow: 15, using: &generator)! < 15) + XCTAssertTrue(Int(randomBelow: 15, using: &generator)! >= 0) + XCTAssertNil(Int(randomBelow: 0, using: &generator)) + XCTAssertNil(Int(randomBelow: -1, using: &generator)) + } } func testTimesMethod() { diff --git a/Tests/HandySwiftTests/Extensions/NSObjectExtTests.swift b/Tests/HandySwiftTests/Extensions/NSObjectExtTests.swift new file mode 100644 index 0000000..391f007 --- /dev/null +++ b/Tests/HandySwiftTests/Extensions/NSObjectExtTests.swift @@ -0,0 +1,13 @@ +// Copyright © 2020 Flinesoft. All rights reserved. + +@testable import HandySwift +import XCTest + +class NSObjectExtTests: XCTestCase { + func testWith() { + #if !os(Linux) + let helloString: NSString? = ("Hello, world".mutableCopy() as? NSMutableString)?.with { $0.append("!") } + XCTAssertEqual(helloString, "Hello, world!") + #endif + } +} diff --git a/Tests/HandySwiftTests/Extensions/NSRangeExtensionTests.swift b/Tests/HandySwiftTests/Extensions/NSRangeExtTests.swift similarity index 94% rename from Tests/HandySwiftTests/Extensions/NSRangeExtensionTests.swift rename to Tests/HandySwiftTests/Extensions/NSRangeExtTests.swift index 527d40b..d317106 100644 --- a/Tests/HandySwiftTests/Extensions/NSRangeExtensionTests.swift +++ b/Tests/HandySwiftTests/Extensions/NSRangeExtTests.swift @@ -3,7 +3,7 @@ @testable import HandySwift import XCTest -class NSRangeExtensionTests: XCTestCase { +class NSRangeExtTests: XCTestCase { func testInitWithSwiftRange() { let testStrings = ["Simple String", "👪 👨‍👩‍👦 👨‍👩‍👧 👨‍👩‍👧‍👦 👨‍👩‍👦‍👦 👨‍👩‍👧‍👧 👨‍👨‍👦 👨‍👨‍👧 👨‍👨‍👧‍👦 👨‍👨‍👦‍👦 👨‍👨‍👧‍👧 👩‍👩‍👦 👩‍👩‍👧 👩‍👩‍👧‍👦 👩‍👩‍👦‍👦 👩‍👩‍👧‍👧"] diff --git a/Tests/HandySwiftTests/Extensions/StringExtensionTests.swift b/Tests/HandySwiftTests/Extensions/StringExtTests.swift similarity index 98% rename from Tests/HandySwiftTests/Extensions/StringExtensionTests.swift rename to Tests/HandySwiftTests/Extensions/StringExtTests.swift index c18b3a4..4bcb9a6 100644 --- a/Tests/HandySwiftTests/Extensions/StringExtensionTests.swift +++ b/Tests/HandySwiftTests/Extensions/StringExtTests.swift @@ -3,7 +3,7 @@ @testable import HandySwift import XCTest -class StringExtensionTests: XCTestCase { +class StringExtTests: XCTestCase { func testStrip() { let whitespaceString = " \n\t BB-8 likes Rey \t\n " XCTAssertEqual(whitespaceString.stripped(), "BB-8 likes Rey") diff --git a/Tests/HandySwiftTests/Extensions/TimeIntervalExtensionTests.swift b/Tests/HandySwiftTests/Extensions/TimeIntervalExtTests.swift similarity index 96% rename from Tests/HandySwiftTests/Extensions/TimeIntervalExtensionTests.swift rename to Tests/HandySwiftTests/Extensions/TimeIntervalExtTests.swift index 3f22dfb..279e3fc 100644 --- a/Tests/HandySwiftTests/Extensions/TimeIntervalExtensionTests.swift +++ b/Tests/HandySwiftTests/Extensions/TimeIntervalExtTests.swift @@ -3,7 +3,7 @@ @testable import HandySwift import XCTest -class TimeIntervalExtensionTests: XCTestCase { +class TimeIntervalExtTests: XCTestCase { func testUnitInitialization() { XCTAssertEqual(Timespan.days(0.5), 12 * 60 * 60, accuracy: 0.001) XCTAssertEqual(Timespan.hours(0.5), 30 * 60, accuracy: 0.001) diff --git a/Tests/HandySwiftTests/Structs/RegexTests.swift b/Tests/HandySwiftTests/Structs/RegexTests.swift index 68537e8..5a6954b 100644 --- a/Tests/HandySwiftTests/Structs/RegexTests.swift +++ b/Tests/HandySwiftTests/Structs/RegexTests.swift @@ -12,11 +12,10 @@ class RegexTests: XCTestCase { } func testInvalidInitialization() { - do { + do { _ = try Regex("*") XCTFail("Regex initialization unexpectedly didn't fail") - } catch { - } + } catch {} } // MARK: - Options @@ -98,7 +97,7 @@ class RegexTests: XCTestCase { let match1 = regex?.firstMatch(in: "2Needed") let match2 = regex?.firstMatch(in: "5NeededOptional") - enum CapturingError: Error { // swiftlint:disable:this nesting + enum CapturingError: Error { case indexTooHigh case noMatch } @@ -120,7 +119,7 @@ class RegexTests: XCTestCase { XCTAssertEqual(match1Capture0, "2") XCTAssertEqual(match1Capture1, "Needed") - XCTAssertEqual(match1Capture2, nil) + XCTAssertNil(match1Capture2) XCTAssertEqual(match2Capture0, "5") XCTAssertEqual(match2Capture1, "Needed") diff --git a/Tests/HandySwiftTests/Structs/SortedArrayTests.swift b/Tests/HandySwiftTests/Structs/SortedArrayTests.swift index 79bdc70..e46b041 100644 --- a/Tests/HandySwiftTests/Structs/SortedArrayTests.swift +++ b/Tests/HandySwiftTests/Structs/SortedArrayTests.swift @@ -49,13 +49,13 @@ class SortedArrayTests: XCTestCase { func testCollectionFeatures() { let intArray: [Int] = [5, 6, 7, 8, 9, 0, 1, 2, 3, 4] let sortedIntArray = SortedArray(intArray) - let expectedElementsSum = intArray.reduce(0) { result, element in return result + element } + let expectedElementsSum = intArray.reduce(0) { result, element in result + element } var forEachElementsSum = 0 sortedIntArray.forEach { forEachElementsSum += $0 } XCTAssertEqual(forEachElementsSum, expectedElementsSum) - let reduceElementsSum = sortedIntArray.reduce(0) { result, element in return result + element } + let reduceElementsSum = sortedIntArray.reduce(0) { result, element in result + element } XCTAssertEqual(reduceElementsSum, expectedElementsSum) let increasedByOneSortedArray = sortedIntArray.map { $0 + 1 } diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 936f458..120f37d 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -1,4 +1,4 @@ -// Generated using Sourcery 0.15.0 — https://github.com/krzysztofzablocki/Sourcery +// Generated using Sourcery 0.17.0 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT @testable import HandySwiftTests @@ -6,8 +6,8 @@ import XCTest // swiftlint:disable line_length file_length -extension ArrayExtensionTests { - static var allTests: [(String, (ArrayExtensionTests) -> () throws -> Void)] = [ +extension ArrayExtTests { + static var allTests: [(String, (ArrayExtTests) -> () throws -> Void)] = [ ("testSample", testSample), ("testSampleWithSize", testSampleWithSize), ("testCombinationsWithOther", testCombinationsWithOther), @@ -16,14 +16,27 @@ extension ArrayExtensionTests { ] } -extension CollectionExtensionTests { - static var allTests: [(String, (CollectionExtensionTests) -> () throws -> Void)] = [ - ("testTrySubscript", testTrySubscript) +extension CollectionExtTests { + static var allTests: [(String, (CollectionExtTests) -> () throws -> Void)] = [ + ("testTrySubscript", testTrySubscript), + ("testSum", testSum), + ("testAverage", testAverage) ] } -extension DictionaryExtensionTests { - static var allTests: [(String, (DictionaryExtensionTests) -> () throws -> Void)] = [ +extension ComparableExtTests { + static var allTests: [(String, (ComparableExtTests) -> () throws -> Void)] = [ + ("testClampedClosedRange", testClampedClosedRange), + ("testClampedPartialRangeFrom", testClampedPartialRangeFrom), + ("testClampedPartialRangeThrough", testClampedPartialRangeThrough), + ("testClampClosedRange", testClampClosedRange), + ("testClampPartialRangeFrom", testClampPartialRangeFrom), + ("testClampPartialRangeThrough", testClampPartialRangeThrough) + ] +} + +extension DictionaryExtTests { + static var allTests: [(String, (DictionaryExtTests) -> () throws -> Void)] = [ ("testInitWithSameCountKeysAndValues", testInitWithSameCountKeysAndValues), ("testInitWithDifferentCountKeysAndValues", testInitWithDifferentCountKeysAndValues), ("testMergeOtherDictionary", testMergeOtherDictionary), @@ -31,8 +44,8 @@ extension DictionaryExtensionTests { ] } -extension DispatchTimeIntervalExtensionTests { - static var allTests: [(String, (DispatchTimeIntervalExtensionTests) -> () throws -> Void)] = [ +extension DispatchTimeIntervalExtTests { + static var allTests: [(String, (DispatchTimeIntervalExtTests) -> () throws -> Void)] = [ ("testTimeInterval", testTimeInterval) ] } @@ -50,14 +63,26 @@ extension GlobalsTests { ] } -extension IntExtensionTests { - static var allTests: [(String, (IntExtensionTests) -> () throws -> Void)] = [ +extension IntExtTests { + static var allTests: [(String, (IntExtTests) -> () throws -> Void)] = [ ("testInitRandomBelow", testInitRandomBelow), ("testTimesMethod", testTimesMethod), ("testTimesMakeMethod", testTimesMakeMethod) ] } +extension NSObjectExtTests { + static var allTests: [(String, (NSObjectExtTests) -> () throws -> Void)] = [ + ("testWith", testWith) + ] +} + +extension NSRangeExtTests { + static var allTests: [(String, (NSRangeExtTests) -> () throws -> Void)] = [ + ("testInitWithSwiftRange", testInitWithSwiftRange) + ] +} + extension RegexTests { static var allTests: [(String, (RegexTests) -> () throws -> Void)] = [ ("testValidInitialization", testValidInitialization), @@ -88,33 +113,45 @@ extension SortedArrayTests { ] } -extension StringExtensionTests { - static var allTests: [(String, (StringExtensionTests) -> () throws -> Void)] = [ +extension StringExtTests { + static var allTests: [(String, (StringExtTests) -> () throws -> Void)] = [ ("testStrip", testStrip), ("testIsBlank", testIsBlank), ("testInitRandomWithLengthAllowedCharactersType", testInitRandomWithLengthAllowedCharactersType), ("testSample", testSample), - ("testSampleWithSize", testSampleWithSize) + ("testSampleWithSize", testSampleWithSize), + ("testFullRange", testFullRange) ] } -extension TimeIntervalExtensionTests { - static var allTests: [(String, (TimeIntervalExtensionTests) -> () throws -> Void)] = [ +extension TimeIntervalExtTests { + static var allTests: [(String, (TimeIntervalExtTests) -> () throws -> Void)] = [ ("testUnitInitialization", testUnitInitialization), ("testUnitConversion", testUnitConversion) ] } +extension WithableTests { + static var allTests: [(String, (WithableTests) -> () throws -> Void)] = [ + ("testInitWith", testInitWith), + ("testWith", testWith) + ] +} + XCTMain([ - testCase(ArrayExtensionTests.allTests), - testCase(CollectionExtensionTests.allTests), - testCase(DictionaryExtensionTests.allTests), - testCase(DispatchTimeIntervalExtensionTests.allTests), + testCase(ArrayExtTests.allTests), + testCase(CollectionExtTests.allTests), + testCase(ComparableExtTests.allTests), + testCase(DictionaryExtTests.allTests), + testCase(DispatchTimeIntervalExtTests.allTests), testCase(FrequencyTableTests.allTests), testCase(GlobalsTests.allTests), - testCase(IntExtensionTests.allTests), + testCase(IntExtTests.allTests), + testCase(NSObjectExtTests.allTests), + testCase(NSRangeExtTests.allTests), testCase(RegexTests.allTests), testCase(SortedArrayTests.allTests), - testCase(StringExtensionTests.allTests), - testCase(TimeIntervalExtensionTests.allTests) + testCase(StringExtTests.allTests), + testCase(TimeIntervalExtTests.allTests), + testCase(WithableTests.allTests) ]) diff --git a/UsageExamples.playground/Contents.swift b/UsageExamples.playground/Contents.swift index 9fb7fcf..575eac7 100644 --- a/UsageExamples.playground/Contents.swift +++ b/UsageExamples.playground/Contents.swift @@ -128,10 +128,12 @@ arrayForTry[try: 20] [0.5, 1.5, 2.5].sum() //: ### .average() -//: Returns the average of all elements as a Double value. -//: NOTE: Only available for `Int` and `Double` collections. +//: Returns the average of all elements. +//: NOTE: For `Int` collections, the average is returned alternatively as a `Double`, `Float` or `CGFloat` value. [10, 20, 30, 40].average() [10.75, 20.75, 30.25, 40.25].average() +let averageAsFloat: Float = [10, 20, 30, 40].average() +averageAsFloat //: ## DictionaryExtension //: ### init?(keys:values:) diff --git a/beak.swift b/beak.swift deleted file mode 100644 index e26bf24..0000000 --- a/beak.swift +++ /dev/null @@ -1,280 +0,0 @@ -// beak: kareman/SwiftShell @ .upToNextMajor(from: "4.0.1") -// beak: kylef/PathKit @ .upToNextMajor(from: "0.9.1") -// beak: onevcat/Rainbow @ .upToNextMajor(from: "3.1.2") -// beak: Flinesoft/HandySwift @ .upToNextMajor(from: "2.6.0") - -import HandySwift -import Foundation -import SwiftShell -import PathKit -import Rainbow - -let supportedPlatforms = ["iOS", "tvOS", "macOS", "watchOS"] - -// MARK: - Helpers -private func deleteFile(_ fileName: String) throws { - let command = "[ ! -e \(fileName) ] || rm \(fileName)" - print("Deleting file '\(fileName)': '\(command)'", level: .info) - try runAndPrint(bash: command) -} - -private func renameProject(from oldName: String, to newName: String) throws { - var filesToReplaceContent: [Path] = [ - Path(oldName + ".xcodeproj/project.pbxproj"), - Path(oldName + ".xcodeproj/project.xcworkspace/contents.xcworkspacedata") - ] - - filesToReplaceContent += supportedPlatforms.map { Path(oldName + ".xcodeproj/xcshareddata/xcschemes/\(oldName) \($0).xcscheme") } - filesToReplaceContent += Path.glob("Sources/**/*.swift") - filesToReplaceContent += Path.glob("Tests/**/*.swift") - filesToReplaceContent += [ - "README.md", "Package.swift", "Sources/Supporting Files/\(oldName).h", "UsageExamples.playground/Contents.swift", - "\(oldName).xcworkspace/contents.xcworkspacedata", "\(oldName).podspec" - ].map { Path($0) } - - try filesToReplaceContent.forEach { swiftFilePath in - try replaceInFile(fileUrl: swiftFilePath.url, regex: try Regex(oldName), replacement: newName) - } - - try supportedPlatforms.forEach { platform in - let oldSchemePath = "\(oldName).xcodeproj/xcshareddata/xcschemes/\(oldName)\\ \(platform).xcscheme" - let newSchemePath = "\(oldName).xcodeproj/xcshareddata/xcschemes/\(newName)\\ \(platform).xcscheme" - try runAndPrint(bash: "mv \(oldSchemePath) \(newSchemePath)") - } - - try runAndPrint(bash: "mv \(oldName).xcodeproj/ \(newName).xcodeproj/") - try runAndPrint(bash: "mv \(oldName).xcworkspace/ \(newName).xcworkspace/") - try runAndPrint(bash: "mv \(oldName).podspec \(newName).podspec") - try runAndPrint(bash: "mv Sources/Supporting\\ Files/\(oldName).h Sources/Supporting\\ Files/\(newName).h") -} - -private func renameOrganization(from oldName: String, to newName: String, projectName: String) throws { - var filesToReplaceContent: [Path] = [ - Path("LICENSE.md"), - Path("README.md"), - Path("\(projectName).podspec"), - Path("\(projectName).xcodeproj/project.pbxproj"), - Path("Sources/Supporting Files/\(projectName).h") - ] - - filesToReplaceContent += Path.glob("Sources/**/*.swift") - filesToReplaceContent += Path.glob("Tests/**/*.swift") - - // replace normal URL appearances - let oldNameWithoutWhitespaces = oldName.components(separatedBy: .whitespaces).joined() - let newNameWithoutWhitespaces = newName.components(separatedBy: .whitespaces).joined() - - let urlRegex = try Regex("\(oldNameWithoutWhitespaces)/") - try filesToReplaceContent.forEach { swiftFilePath in - try replaceInFile(fileUrl: swiftFilePath.url, regex: urlRegex, replacement: "\(newNameWithoutWhitespaces)/") - } - - // replace reversed URl appearances - let reversedUrlRegex = try Regex("com.\(oldNameWithoutWhitespaces.lowercased())") - try filesToReplaceContent.forEach { swiftFilePath in - try replaceInFile(fileUrl: swiftFilePath.url, regex: reversedUrlRegex, replacement: "com.\(newNameWithoutWhitespaces.lowercased())") - } - - // replace other - try filesToReplaceContent.forEach { swiftFilePath in - try replaceInFile(fileUrl: swiftFilePath.url, regex: try Regex(oldName), replacement: newName) - } -} - -private func replaceInFile(fileUrl: URL, regex: Regex, replacement: String) throws { - print("Replacing occurences of regex '\(regex)' in file '\(fileUrl.lastPathComponent)' with '\(replacement)' ...", level: .info) - var content = try String(contentsOf: fileUrl, encoding: .utf8) - content = regex.replacingMatches(in: content, with: replacement) - try content.write(to: fileUrl, atomically: false, encoding: .utf8) -} - -private func replaceInFile(fileUrl: URL, substring: String, replacement: String) throws { - print("Replacing occurences of substring '\(substring)' in file '\(fileUrl.lastPathComponent)' with '\(replacement)' ...", level: .info) - var content = try String(contentsOf: fileUrl, encoding: .utf8) - content = content.replacingOccurrences(of: substring, with: replacement) - try content.write(to: fileUrl, atomically: false, encoding: .utf8) -} - -private enum PrintLevel { - case info - case warning - case error -} - -private func print(_ message: String, level: PrintLevel) { - switch level { - case .info: - print("ℹ️ ", message.lightBlue) - - case .warning: - print("⚠️ ", message.yellow) - - case .error: - print("❌ ", message.red) - } -} - -private let semanticVersionRegex = try Regex("(\\d+)\\.(\\d+)\\.(\\d+)\\s") - -private struct SemanticVersion: Comparable, CustomStringConvertible { - let major: Int - let minor: Int - let patch: Int - - init(_ string: String) { - guard let captures = semanticVersionRegex.firstMatch(in: string)?.captures else { - fatalError("SemanticVersion initializer was used without checking the structure.") - } - - major = Int(captures[0]!)! - minor = Int(captures[1]!)! - patch = Int(captures[2]!)! - } - - static func < (lhs: SemanticVersion, rhs: SemanticVersion) -> Bool { - guard lhs.major == rhs.major else { return lhs.major < rhs.major } - guard lhs.minor == rhs.minor else { return lhs.minor < rhs.minor } - return lhs.patch < rhs.patch - } - - static func == (lhs: SemanticVersion, rhs: SemanticVersion) -> Bool { - return lhs.major == rhs.major && lhs.minor == rhs.minor && lhs.patch == rhs.patch - } - - var description: String { - return "\(major).\(minor)" - } -} - -private func appendEntryToCartfile(_ tagline: String?, _ githubSubpath: String, _ version: String) throws { - let comment = tagline != nil ? "# \(tagline!)\n" : "" - let repoSpecifier = "github \"\(githubSubpath)\"" - let versionSpecifier: String = { - guard version != "latest" else { - let tagListCommand = "git ls-remote --tags https://github.com/\(githubSubpath).git" - let commandOutput = run(bash: tagListCommand).stdout - let availableSemanticVersions = semanticVersionRegex.matches(in: commandOutput).map { SemanticVersion($0.string) } - guard !availableSemanticVersions.isEmpty else { - print("Dependency '\(githubSubpath)' has no tagged versions.", level: .error) - fatalError() - } - let latestVersion = availableSemanticVersions.sorted().last! - return " ~> \(latestVersion)" - } - - return " ~> \(version)" - }() - - let textToAddToCartfile = "\n\(comment)\(repoSpecifier)\(versionSpecifier)\n" - - let command = "echo '\(textToAddToCartfile)' >> Cartfile" - print("Adding entry to Cartfile with: '\(command)'", level: .info) - try runAndPrint(bash: command) -} - -private func fetchGitHubTagline(subpath: String) throws -> String? { - let taglineRegex = try Regex("[^\\:]+\\: (.*)<\\/title>") - let url = URL(string: "https://github.com/\(subpath)")! - let html = try String(contentsOf: url, encoding: .utf8) - guard let firstMatch = taglineRegex.firstMatch(in: html) else { return nil } - guard let firstCapture = firstMatch.captures.first else { return nil } - return firstCapture! -} - -private func pathOfXcodeProject() -> Path { - return Path.current.glob("*.xcodeproj").first! -} - -typealias Framework = (identifier: String, name: String) - -private func pbxProjectFilePath() -> Path { - return pathOfXcodeProject() + Path("project.pbxproj") -} - -private func pbxProjectFileContent() throws -> String { - return try pbxProjectFilePath().read(.utf8) -} - -private struct CartfileEntry: CustomStringConvertible { - let commentLine: String? - let dependencyDefinitionLine: String - - var description: String { - guard let commentLine = commentLine else { return dependencyDefinitionLine } - return [commentLine, dependencyDefinitionLine].joined(separator: "\n") - } -} - -// MARK: - Tasks -/// Initializes the project with the given info. -public func initialize(projectName: String, organization: String) throws { - try ["README.md", "Logo.png"].forEach { try deleteFile($0) } - try runAndPrint(bash: "mv README.md.sample README.md") - try renameProject(from: "NewFrameworkTemplate", to: projectName) - try renameOrganization(from: "Flinesoft", to: organization, projectName: projectName) - try installDependencies() -} - -/// Installs project dependencies. -public func installDependencies() throws { - let command = "carthage bootstrap --platform \(supportedPlatforms.joined(separator: ",")) --cache-builds" - print("Installing dependencies via Carthage: '\(command)'", level: .info) - try runAndPrint(bash: command) -} - -/// Updates project dependencies. -public func updateDependencies() throws { - let command = "carthage update --platform \(supportedPlatforms.joined(separator: ",")) --cache-builds" - print("Updating dependencies via Carthage: \(command)", level: .info) - try runAndPrint(bash: command) -} - -/// Adds a dependency using the configured package manager. -public func addDependency(github githubSubpath: String, version: String = "latest") throws { - let tagline = try fetchGitHubTagline(subpath: githubSubpath) - try appendEntryToCartfile(tagline, githubSubpath, version) - try sortCartfile() - try updateDependencies() - - print("Please add the new frameworks to your projects 'Carthage >> Framework' groups related platforms in the project navigator.", level: .warning) - - run(bash: "open -a Finder Carthage/Build/") -} - -/// Sorts the contents of Cartfile and Cartfile.private. -public func sortCartfile() throws { - let dependecyLineRegex = try Regex("#? ?(?:github|binary|git) \"[^\"]+/([^\"]+)\".*") - - try ["Cartfile", "Cartfile.private"].forEach { fileName in - let cartfileContents = try String(contentsOfFile: fileName) - let cartfileLines = cartfileContents.components(separatedBy: .newlines).filter { !$0.isBlank } - - var temporaryComment: String? - let cartfileEntries: [CartfileEntry] = cartfileLines.compactMap { line in - if dependecyLineRegex.matches(line) { - let newEntry = CartfileEntry(commentLine: temporaryComment, dependencyDefinitionLine: line) - temporaryComment = nil - return newEntry - } else { - temporaryComment = line - return nil - } - } - - let compareClosure = { (lhs: CartfileEntry, rhs: CartfileEntry) -> Bool in - let lhsDependencyName = dependecyLineRegex.firstMatch(in: lhs.dependencyDefinitionLine)!.captures.first!!.lowercased() - let rhsDependencyName = dependecyLineRegex.firstMatch(in: rhs.dependencyDefinitionLine)!.captures.first!!.lowercased() - return lhsDependencyName < rhsDependencyName - } - - let sortedCartfilEntries = cartfileEntries.sorted(by: compareClosure, stable: false) - let newCartfileContents = sortedCartfilEntries.map { $0.description }.joined(separator: "\n\n") + "\n" - try newCartfileContents.write(toFile: fileName, atomically: false, encoding: .utf8) - } -} - -/// Generates the LinuxMain.swift file by automatically searching the Tests path for tests. -public func generateLinuxMain() { - run("sourcery --sources Tests --templates .sourcery/LinuxMain.stencil --output .sourcery --force-parse generated") - run("mv .sourcery/LinuxMain.generated.swift Tests/LinuxMain.swift") -}