New Upstream Release - ruby-necromancer
Ready changes
Summary
Merged new upstream version: 0.7.0 (was: 0.5.1).
Resulting package
Built on 2022-12-29T18:13 (took 4m14s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases ruby-necromancer
Lintian Result
Diff
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..2bb2923
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,9 @@
+root = true
+
+[*.rb]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..06ec573
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+github: piotrmurach
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..78ece6f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,23 @@
+### Are you in the right place?
+* For issues or feature requests file a GitHub issue in this repository
+* For general questions or discussion post on StackOverflow
+
+### Describe the problem
+A brief description of the issue/feature.
+
+### Steps to reproduce the problem
+```
+Your code here to reproduce the issue
+```
+
+### Actual behaviour
+What happened? This could be a description, log output, error raised etc...
+
+### Expected behaviour
+What did you expect to happen?
+
+### Describe your environment
+
+* OS version:
+* Ruby version:
+* Necromancer version:
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..e07f4b7
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,19 @@
+### Describe the change
+What does this Pull Request do?
+
+### Why are we doing this?
+Any related context as to why is this is a desirable change.
+
+### Benefits
+How will the library improve?
+
+### Drawbacks
+Possible drawbacks applying this change.
+
+### Requirements
+Put an X between brackets on each line if you have done the item:
+
+- [ ] Tests written & passing locally?
+- [ ] Code style checked?
+- [ ] Rebased with `master` branch?
+- [ ] Documentation updated?
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..d2e3d64
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,56 @@
+---
+name: CI
+on:
+ push:
+ branches:
+ - master
+ paths-ignore:
+ - "bin/**"
+ - "*.md"
+ pull_request:
+ branches:
+ - master
+ paths-ignore:
+ - "bin/**"
+ - "*.md"
+jobs:
+ tests:
+ name: Ruby ${{ matrix.ruby }}
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - ubuntu-latest
+ ruby:
+ - 2.1
+ - 2.2
+ - 2.3
+ - 2.4
+ - 2.5
+ - 2.6
+ - 3.0
+ - ruby-head
+ - jruby-9.2.13.0
+ - jruby-head
+ - truffleruby-head
+ include:
+ - ruby: 2.7
+ os: ubuntu-latest
+ coverage: true
+ env:
+ COVERAGE: ${{ matrix.coverage }}
+ COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
+ continue-on-error: ${{ endsWith(matrix.ruby, 'head') }}
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: ${{ matrix.ruby }}
+ - name: Install bundler
+ run: gem install bundler -v '< 2.0'
+ - name: Install dependencies
+ run: bundle install --jobs 4 --retry 3
+ - name: Run tests
+ run: bundle exec rake ci
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ae3fdc2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+/.bundle/
+/.yardoc
+/Gemfile.lock
+/_yardoc/
+/coverage/
+/doc/
+/pkg/
+/spec/reports/
+/tmp/
+*.bundle
+*.so
+*.o
+*.a
+mkmf.log
diff --git a/.rspec b/.rspec
new file mode 100644
index 0000000..65122f0
--- /dev/null
+++ b/.rspec
@@ -0,0 +1,3 @@
+--color
+--require spec_helper
+--warnings
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000..714bba5
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,58 @@
+AllCops:
+ NewCops: enable
+
+Layout/FirstArrayElementIndentation:
+ EnforcedStyle: consistent
+
+Layout/HashAlignment:
+ EnforcedHashRocketStyle: table
+
+Layout/LineLength:
+ Max: 82
+
+Lint/AssignmentInCondition:
+ Enabled: false
+
+Metrics/AbcSize:
+ Max: 30
+
+Metrics/BlockLength:
+ CountComments: true
+ Max: 25
+ IgnoredMethods: []
+ Exclude:
+ - "spec/**/*"
+
+Metrics/ClassLength:
+ Max: 1500
+
+Metrics/CyclomaticComplexity:
+ Enabled: false
+
+Metrics/MethodLength:
+ Max: 20
+
+Naming/BinaryOperatorParameterName:
+ Enabled: false
+
+Style/AccessorGrouping:
+ Enabled: false
+
+Style/AsciiComments:
+ Enabled: false
+
+Style/LambdaCall:
+ EnforcedStyle: braces
+
+Style/StringLiterals:
+ EnforcedStyle: double_quotes
+
+Style/TrivialAccessors:
+ Enabled: false
+
+# { ... } for multi-line blocks is okay
+Style/BlockDelimiters:
+ Enabled: false
+
+Style/CommentedKeyword:
+ Enabled: false
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5f8f2ca..b6561b0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
# Change log
+## [v0.7.0] - 2020-12-29
+
+### Added
+* Add HashConverters for transforming string into hash of string, integer, float or boolean values
+* Add converters for transforming string to array of booleans, integers, floats and numeric
+
+### Changed
+* Change StringToRange converter to work with decimal numbers and spaces
+* Change :strict to be a keyword argument
+* Change StringToNumeric converter to allow numbers with space characters
+
+## [v0.6.0] - 2020-03-08
+
+### Changed
+* Change gemspec to remove test artifacts
+
## [v0.5.1] - 2019-11-24
### Changed
@@ -52,6 +68,8 @@
* Initial implementation and release
+[v0.7.0]: https://github.com/piotrmurach/necromancer/compare/v0.6.0...v0.7.0
+[v0.6.0]: https://github.com/piotrmurach/necromancer/compare/v0.5.1...v0.6.0
[v0.5.1]: https://github.com/piotrmurach/necromancer/compare/v0.5.0...v0.5.1
[v0.5.0]: https://github.com/piotrmurach/necromancer/compare/v0.4.0...v0.5.0
[v0.4.0]: https://github.com/piotrmurach/necromancer/compare/v0.3.0...v0.4.0
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..c22634c
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,74 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of experience,
+nationality, personal appearance, race, religion, or sexual identity and
+orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at piotr@piotrmurach.com. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at [https://contributor-covenant.org/version/1/4][version]
+
+[homepage]: https://contributor-covenant.org
+[version]: https://contributor-covenant.org/version/1/4/
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..6112c23
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,12 @@
+source "https://rubygems.org"
+
+gemspec
+
+gem "simplecov", "~> 0.16.1"
+gem "coveralls", "~> 0.8.22"
+gem "yardstick", "~> 0.9.9"
+gem "json", "2.4.1" if RUBY_VERSION == "2.0.0"
+
+group :development do
+ gem "benchmark-ips", "~> 2.7.2"
+end
diff --git a/README.md b/README.md
index 88075f3..f727907 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,14 @@
# Necromancer
[![Gem Version](https://badge.fury.io/rb/necromancer.svg)][gem]
-[![Build Status](https://secure.travis-ci.org/piotrmurach/necromancer.svg?branch=master)][travis]
+[![Actions CI](https://github.com/piotrmurach/tty-runner/workflows/CI/badge.svg?branch=master)][gh_actions_ci]
[![Build status](https://ci.appveyor.com/api/projects/status/qj3xn5gbbfi4puet?svg=true)][appveyor]
[![Code Climate](https://codeclimate.com/github/piotrmurach/necromancer/badges/gpa.svg)][codeclimate]
[![Coverage Status](https://coveralls.io/repos/github/piotrmurach/necromancer/badge.svg?branch=master)][coverage]
[![Inline docs](http://inch-ci.org/github/piotrmurach/necromancer.svg?branch=master)][inchpages]
[gem]: http://badge.fury.io/rb/necromancer
-[travis]: http://travis-ci.org/piotrmurach/necromancer
+[gh_actions_ci]: https://github.com/piotrmurach/tty-runner/actions?query=workflow%3ACI
[appveyor]: https://ci.appveyor.com/project/piotrmurach/necromancer
[codeclimate]: https://codeclimate.com/github/piotrmurach/necromancer
[coverage]: https://coveralls.io/github/piotrmurach/necromancer
@@ -35,7 +35,7 @@ Conversion between Ruby core types frequently comes up in projects but is solved
Add this line to your application's Gemfile:
```ruby
-gem 'necromancer'
+gem "necromancer"
```
And then execute:
@@ -73,39 +73,48 @@ Or install it yourself as:
For example, to convert a string to a [range](#36-range) type:
```ruby
-Necromancer.convert('1-10').to(:range) # => 1..10
-Necromancer.convert('1-10') >> :range # => 1..10
-Necromancer.convert('1-10') >> Range # => 1..10
+Necromancer.convert("1-10").to(:range) # => 1..10
+Necromancer.convert("1-10") >> :range # => 1..10
+Necromancer.convert("1-10") >> Range # => 1..10
```
In order to handle [boolean](#32-boolean) conversions:
```ruby
-Necromancer.convert('t').to(:boolean) # => true
-Necromancer.convert('t') >> true # => true
+Necromancer.convert("t").to(:boolean) # => true
+Necromancer.convert("t") >> true # => true
```
To convert string to [numeric](#35-numeric) value:
```ruby
-Necromancer.convert('10e1').to(:numeric) # => 100
+Necromancer.convert("10e1").to(:numeric) # => 100
```
-or convert [array](#31-array) of string values into numeric type:
+You can convert string to [array](#31-array) of values like `boolean`, `integer` or `float`:
```ruby
-Necromancer.convert(['1', '2.3', '3.0']).to(:numeric) # => [1, 2.3, 3.0]
+Necromancer.convert("t,f,t"]).to(:booleans) # => [true, false, true]
+Necromancer.convert("1,2.3,3.0"]).to(:integers) # => [1, 2, 3]
+Necromancer.convert("1,2.3,3.0"]).to(:floats) # => [1.0, 2.3, 3.0]
```
-To provide extra information about the conversion value type you can use `from`.
+To convert string to [hash](#34-hash) value:
```ruby
-Necromancer.convert(['1', '2.3', '3.0']).from(:array).to(:numeric) # => [1, 2.3, 3.0]
+Necromancer.convert("a:1 b:2 c:3").to(:hash) # => {a: "1", b: "2", c: "3"}
+Necromancer.convert("a=1 b=2 c=3").to(:hash) # => {a: "1", b: "2", c: "3"}
+````
+
+To provide extra information about the conversion value type use the `from`:
+
+```ruby
+Necromancer.convert(["1", "2.3", "3.0"]).from(:array).to(:numeric) # => [1, 2.3, 3.0]
```
**Necromancer** also allows you to add [custom](#37-custom) conversions.
-Conversion isn't always possible, in which case a `Necromancer::NoTypeConversionAvailableError` is thrown indicating that `convert` doesn't know how to perform the requested conversion:
+When conversion isn't possible, a `Necromancer::NoTypeConversionAvailableError` is thrown indicating that `convert` doesn't know how to perform the requested conversion:
```ruby
Necromancer.convert(:foo).to(:float)
@@ -121,13 +130,13 @@ Necromancer.convert(:foo).to(:float)
For the purpose of divination, **Necromancer** uses `convert` method to turn source type into target type. For example, in order to convert a string into a range type do:
```ruby
-Necromancer.convert('1,10').to(:range) # => 1..10
+Necromancer.convert("1,10").to(:range) # => 1..10
```
Alternatively, you can use block:
```ruby
-Necromancer.convert { '1,10' }.to(:range) # => 1..10
+Necromancer.convert { "1,10" }.to(:range) # => 1..10
```
Conversion isn't always possible, in which case a `Necromancer::NoTypeConversionAvailableError` is thrown indicating that `convert` doesn't know how to perform the requested conversion:
@@ -142,54 +151,54 @@ Necromancer.convert(:foo).to(:float)
To specify conversion source type use `from` method:
```ruby
-Necromancer.convert('1.0').from(:string).to(:numeric)
+Necromancer.convert("1.0").from(:string).to(:numeric)
```
In majority of cases you do not need to specify `from` as the type will be inferred from the `convert` method argument and then appropriate conversion will be applied to result in `target` type such as `:numeric`. However, if you do not control the input to `convert` and want to ensure consistent behaviour please use `from`.
The source parameters are:
-* :array
-* :boolean
-* :date
-* :datetime
-* :float
-* :integer
-* :numeric
-* :range
-* :string
-* :time
+* `:array`
+* `:boolean`
+* `:date`
+* `:datetime`
+* `:float`
+* `:integer`
+* `:numeric`
+* `:range`
+* `:string`
+* `:time`
### 2.3 to
To convert objects between types, **Necromancer** provides several target types. The `to` or functional style `>>` method allows you to pass target as an argument to perform actual conversion. The target can be one of `:symbol`, `object` or `ClassName`:
```ruby
-Necromancer.convert('yes').to(:boolean) # => true
-Necromancer.convert('yes') >> :boolean # => true
-Necromancer.convert('yes') >> true # => true
-Necromancer.convert('yes') >> TrueClass # => true
+Necromancer.convert("yes").to(:boolean) # => true
+Necromancer.convert("yes") >> :boolean # => true
+Necromancer.convert("yes") >> true # => true
+Necromancer.convert("yes") >> TrueClass # => true
```
-By default, when target conversion fails the orignal value is returned. However, you can pass `strict` as an additional argument to ensure failure when conversion cannot be performed:
+By default, when target conversion fails the original value is returned. However, you can pass `strict` as an additional argument to ensure failure when conversion cannot be performed:
```ruby
-Necromancer.convert('1a').to(:integer, strict: true)
+Necromancer.convert("1a").to(:integer, strict: true)
# => raises Necromancer::ConversionTypeError
```
The target parameters are:
-* :array
-* :boolean
-* :date
-* :datetime
-* :float
-* :integer
-* :numeric
-* :range
-* :string
-* :time
+* `:array`
+* `:boolean`, `:booleans`, `:bools`, `:boolean_hash`, `:bool_hash`
+* `:date`
+* `:datetime`,
+* `:float`, `:floats`, `:float_hash`
+* `:integer`, `:integers`, `:ints`, `:integer_hash`, `:int_hash`
+* `:numeric`, `:numerics`, `:nums`, `:numeric_hash`, `:num_hash`
+* `:range`
+* `:string`
+* `:time`
### 2.4 can?
@@ -211,7 +220,7 @@ Necromancer.new do |config|
end
```
-or calling `configure` method:
+Or calling `configure` method:
```ruby
converter = Necromancer.new
@@ -222,12 +231,12 @@ end
Available configuration options are:
-* strict - ensures correct types for conversion, by default `false`
-* copy - ensures only copy is modified, by default `true`
+* `strict` - ensures correct types for conversion, by default `false`
+* `copy` - ensures only copy is modified, by default `true`
## 3. Converters
-**Necromancer** flexibility means you can register your own converters or use the already defined converters for such types as `Array`, `Boolean`, `Hash`, `Numeric`, `Range`.
+**Necromancer** flexibility means you can register your own converters or use the already defined converters for such types as `Array`, `Boolean`, `Date`, `DateTime`, `Hash`, `Numeric`, `Range` and `Time`.
### 3.1 Array
@@ -241,47 +250,61 @@ Necromancer.convert({x: 1}).to(:array) # => [[:x, 1]]
In addition, **Necromancer** excels at converting `,` or `-` delimited string into an array object:
```ruby
-Necromancer.convert('a, b, c').to(:array) # => ['a', 'b', 'c']
+Necromancer.convert("a, b, c").to(:array) # => ["a", "b", "c"]
```
If the string is a list of `-` or `,` separated numbers, they will be converted to their respective numeric types:
```ruby
-Necromancer.convert('1 - 2 - 3').to(:array) # => [1, 2, 3]
+Necromancer.convert("1 - 2 - 3").to(:array) # => [1, 2, 3]
+```
+
+It handles conversion of string into an array of boolean values as well:
+
+```ruby
+Necromancer.convert("yes,no,t").to(:booleans) # => [true, false, true]
+Necromancer.convert("1 - f - FALSE").to(:bools) # => [true, false, false]
```
You can also convert array containing string objects to array containing numeric values:
```ruby
-Necromancer.convert(['1', '2.3', '3.0']).to(:numeric)
+Necromancer.convert(["1", "2.3", "3.0"]).to(:numerics) # => [1, 2.3, 3.0]
+Necromancer.convert(["1", "2.3", "3.0"]).to(:nums) # => [1, 2.3, 3.0]
+```
+
+Or you can be more specific by using `:integers` and `:floats` as the resulting type:
+
+```ruby
+Necromancer.convert(["1", "2.3", "3.0"]).to(:integers) # => [1, 2, 3]
```
When in `strict` mode the conversion will raise a `Necromancer::ConversionTypeError` error like so:
```ruby
-Necromancer.convert(['1', '2.3', false]).to(:numeric, strict: true)
-# => Necromancer::ConversionTypeError: false cannot be converted from `array` to `numeric`
+Necromancer.convert(["1", "2.3", false]).to(:numerics, strict: true)
+# => Necromancer::ConversionTypeError: false cannot be converted from `array` to `numerics`
```
However, in `non-strict` mode the value will be simply returned unchanged:
```ruby
-Necromancer.convert(['1', '2.3', false]).to(:numeric, strict: false)
+Necromancer.convert(["1", "2.3", false]).to(:numerics, strict: false)
# => [1, 2.3, false]
```
### 3.2 Boolean
-The **Necromancer** allows you to convert a string object to boolean object. The `1`, `'1'`, `'t'`, `'T'`, `'true'`, `'TRUE'`, `'y'`, `'Y'`, `'yes'`, `'Yes'`, `'on'`, `'ON'` values are converted to `TrueClass`.
+The **Necromancer** allows you to convert a string object to boolean object. The `1`, `"1"`, `"t"`, `"T"`, `"true"`, `"TRUE"`, `"y"`, `"Y"`, `"yes"`, `"Yes"`, `"on"`, `"ON"` values are converted to `TrueClass`.
```ruby
-Necromancer.convert('yes').to(:boolean) # => true
+Necromancer.convert("yes").to(:boolean) # => true
```
-Similarly, the `0`, `'0'`, `'f'`, `'F'`, `'false'`, `'FALSE'`, `'n'`, `'N'`, `'no'`, `'No'`, `'off'`, `'OFF'` values are converted to `FalseClass`.
+Similarly, the `0`, `"0"`, `"f"`, `"F"`, `"false"`, `"FALSE"`, `"n"`, `"N"`, `"no"`, `"No"`, `"off"`, `"OFF"` values are converted to `FalseClass`.
```ruby
-Necromancer.convert('no').to(:boolean) # => false
+Necromancer.convert("no").to(:boolean) # => false
```
You can also convert an integer object to boolean:
@@ -296,8 +319,8 @@ Necromancer.convert(0).to(:boolean) # => false
**Necromancer** knows how to convert string to `date` object:
```ruby
-Necromancer.convert('1-1-2015').to(:date) # => "2015-01-01"
-Necromancer.convert('01/01/2015').to(:date) # => "2015-01-01"
+Necromancer.convert("1-1-2015").to(:date) # => "2015-01-01"
+Necromancer.convert("01/01/2015").to(:date) # => "2015-01-01"
```
You can also convert string to `datetime`:
@@ -317,9 +340,39 @@ Necromancer.convert("12:35").to(:time) # => 2015-01-04 12:35:00 +0100
### 3.4 Hash
+With **Necromancer** you can convert a string with pairs delimited by `=` or `:` characters into a hash:
+
+```ruby
+Necromancer.convert("a:1 b:2 c:3").to(:hash)
+Necromancer.convert("a=1 b=2 c=3").to(:hash)
+# => {a: "1", b: "2", c: "3"}
+```
+
+The pairs can be separated by `&` symbols and mix `=` and `:` pair delimiters:
+
+```ruby
+Necromancer.convert("a:1 & b=2 & c:3").to(:hash)
+# => {a: "1", b: "2", c: "3"}
+```
+
+You can also convert string to hash with integer values using `:int_hash` type:
+
+```ruby
+Necromancer.convert("a:1 b:2 c:3").to(:int_hash) # => {a: 1, b: 2, c: 3}
+Necromancer.convert("a:1 b:2 c:3").to(:integer_hash) # => {a: 1, b: 2, c: 3}
+```
+
+Similarly you can convert string to hash with `float` or `numeric` values using `:float_hash` and `numeric_hash` types:
+
+```ruby
+Necromancer.convert("a:1 b:2 c:3").to(:float_hash) # => {a: 1.0, b: 2.0, c: 3.0}
+Necromancer.convert("a:1 b:2.0 c:3").to(:num_hash) # => {a: 1, b:2.0, c: 3}
+```
+
+String can also be converted to hash with boolean values using `:boolean_hash` or `:bool_hash`:
+
```ruby
-Necromancer.convert({ x: '27.5', y: '4', z: '11'}).to(:numeric)
-# => { x: 27.5, y: 4, z: 11}
+Necromancer.convert("a:yes b:no c:t").to(:bool_hash) # => {a: true, b: false, c: true}
```
### 3.5 Numeric
@@ -329,25 +382,25 @@ Necromancer.convert({ x: '27.5', y: '4', z: '11'}).to(:numeric)
To convert a string to a float do:
```ruby
-Necromancer.convert('1.2a').to(:float) # => 1.2
+Necromancer.convert("1.2a").to(:float) # => 1.2
```
Conversion to numeric in strict mode raises `Necromancer::ConversionTypeError`:
```ruby
-Necromancer.convert('1.2a').to(:float, strict: true) # => raises error
+Necromancer.convert("1.2a").to(:float, strict: true) # => raises error
```
To convert a string to an integer do:
```ruby
-Necromancer.convert('1a').to(:integer) # => 1
+Necromancer.convert("1a").to(:integer) # => 1
```
However, if you want to convert string to an appropriate matching numeric type do:
```ruby
-Necromancer.convert('1e1').to(:numeric) # => 10
+Necromancer.convert("1e1").to(:numeric) # => 10
```
### 3.6 Range
@@ -355,15 +408,22 @@ Necromancer.convert('1e1').to(:numeric) # => 10
**Necromancer** is no stranger to figuring out ranges from strings. You can pass `,`, `-`, `..`, `...` characters to denote ranges:
```ruby
-Necromancer.convert('1,10').to(:range) # => 1..10
+Necromancer.convert("1,10").to(:range) # => 1..10
```
-or to create a range of letters:
+Or to create a range of letters:
```ruby
-Necromancer.convert('a-z').to(:range) # => 'a'..'z'
+Necromancer.convert("a-z").to(:range) # => "a".."z"
```
+It will handle space characters:
+
+```ruby
+Necromancer.convert("1 . . 10") >> :range # => 1..10
+Necromancer.convert("a . . . z") >> :range # => "a"..."z"
+````
+
### 3.7 Custom
In case where provided conversions do not match your needs you can create your own and `register` with **Necromancer** by using an `Object` or a `Proc`.
@@ -398,7 +458,7 @@ converter.register(upcase_converter) # => true if successfully registered
Finally, by invoking `convert` method and specifying `:upcase` as the target for the conversion we achieve the result:
```ruby
-converter.convert('magic').to(:upcase) # => 'MAGIC'
+converter.convert("magic").to(:upcase) # => "MAGIC"
```
#### 3.7.2 Using a Proc
@@ -418,7 +478,7 @@ end
Then by invoking the `convert` method and passing the `:upcase` conversion type you can transform the string like so:
```ruby
-converter.convert('magic').to(:upcase) # => 'MAGIC'
+converter.convert("magic").to(:upcase) # => "MAGIC"
```
## Contributing
diff --git a/Rakefile b/Rakefile
index d5eb532..af3337a 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,8 +1,10 @@
-require 'bundler/gem_tasks'
+# frozen_string_literal: true
-FileList['tasks/**/*.rake'].each(&method(:import))
+require "bundler/gem_tasks"
-desc 'Run all specs'
-task ci: %w[ spec ]
+FileList["tasks/**/*.rake"].each(&method(:import))
+
+desc "Run all specs"
+task ci: %w[spec]
task default: :spec
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..8319665
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,32 @@
+---
+skip_commits:
+ files:
+ - "bin/**"
+ - "*.md"
+install:
+ - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
+ - gem install bundler -v '< 2.0'
+ - bundle install --jobs 4 --retry 3
+before_test:
+ - ruby -v
+ - gem -v
+ - bundle -v
+build: off
+test_script:
+ - bundle exec rake ci
+environment:
+ matrix:
+ - ruby_version: "200"
+ - ruby_version: "200-x64"
+ - ruby_version: "21"
+ - ruby_version: "21-x64"
+ - ruby_version: "22"
+ - ruby_version: "22-x64"
+ - ruby_version: "23"
+ - ruby_version: "23-x64"
+ - ruby_version: "24"
+ - ruby_version: "24-x64"
+ - ruby_version: "25"
+ - ruby_version: "25-x64"
+ - ruby_version: "26"
+ - ruby_version: "26-x64"
diff --git a/bin/console b/bin/console
new file mode 100755
index 0000000..1c9c29f
--- /dev/null
+++ b/bin/console
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+
+require "bundler/setup"
+require "necromancer"
+
+# You can add fixtures and/or initialization code here to make experimenting
+# with your gem easier. You can also use a different console, if you like.
+
+# (If you use this, don't forget to add pry to your Gemfile!)
+# require "pry"
+# Pry.start
+
+require "irb"
+IRB.start(__FILE__)
diff --git a/bin/setup b/bin/setup
new file mode 100755
index 0000000..dce67d8
--- /dev/null
+++ b/bin/setup
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -euo pipefail
+IFS=$'\n\t'
+set -vx
+
+bundle install
+
+# Do any other automated setup that you need to do here
diff --git a/debian/changelog b/debian/changelog
index 196f617..7e4c3df 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,10 +1,12 @@
-ruby-necromancer (0.5.1-3) UNRELEASED; urgency=low
+ruby-necromancer (0.7.0-1) UNRELEASED; urgency=low
* Set field Upstream-Contact in debian/copyright.
* Remove obsolete fields Contact, Name from debian/upstream/metadata (already
present in machine-readable debian/copyright).
+ * New upstream release.
+ * Drop patch bring_back_dot_rspec, present upstream.
- -- Debian Janitor <janitor@jelmer.uk> Sat, 29 Aug 2020 23:59:39 -0000
+ -- Debian Janitor <janitor@jelmer.uk> Thu, 29 Dec 2022 18:09:35 -0000
ruby-necromancer (0.5.1-2) unstable; urgency=medium
diff --git a/debian/patches/bring_back_dot_rspec b/debian/patches/bring_back_dot_rspec
deleted file mode 100644
index 00e0a92..0000000
--- a/debian/patches/bring_back_dot_rspec
+++ /dev/null
@@ -1,21 +0,0 @@
-Description: The .rspec file is missing from the released gem
- The github repository for this library contains a .rspec file that makes it
- possible to run tests on the source code. However, it is currently not
- released within the gem file published on rubygems.org. This makes it
- impossible for the debian package build process to run tests without failing.
- .
- The file content is what can currently be found in the git repository for tag
- 0.5.1.
- .
- ruby-necromancer (0.5.1-1) UNRELEASED; urgency=medium
- .
- * Initial release (Closes: #939307)
-Author: Gabriel Filion <gabriel@koumbit.org>
-Bug-Debian: https://bugs.debian.org/939307
-
---- /dev/null
-+++ ruby-necromancer-0.5.1/.rspec
-@@ -0,0 +1,3 @@
-+--color
-+--require spec_helper
-+--warnings
diff --git a/debian/patches/series b/debian/patches/series
index 9c7f614..e69de29 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +0,0 @@
-bring_back_dot_rspec
diff --git a/lib/necromancer.rb b/lib/necromancer.rb
index 4007130..6d5f07c 100644
--- a/lib/necromancer.rb
+++ b/lib/necromancer.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
-require_relative 'necromancer/context'
-require_relative 'necromancer/version'
+require_relative "necromancer/context"
+require_relative "necromancer/version"
module Necromancer
# Raised when cannot conver to a given type
@@ -26,7 +26,8 @@ module Necromancer
# Convenience to directly call conversion
#
# @example
- # Necromancer.convert('1').to(:integer)
+ # Necromancer.convert("1").to(:integer)
+ # # => 1
#
# @return [ConversionTarget]
#
diff --git a/lib/necromancer/context.rb b/lib/necromancer/context.rb
index 1a5124f..dfe093c 100644
--- a/lib/necromancer/context.rb
+++ b/lib/necromancer/context.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
-require 'forwardable'
+require "forwardable"
-require_relative 'configuration'
-require_relative 'conversions'
-require_relative 'conversion_target'
+require_relative "configuration"
+require_relative "conversions"
+require_relative "conversion_target"
module Necromancer
# A class used by Necromancer to provide user interace
@@ -19,7 +19,7 @@ module Necromancer
#
# @api private
def initialize(&block)
- block.call(configuration) if block_given?
+ block.(configuration) if block_given?
@conversions = Conversions.new(configuration)
@conversions.load
end
diff --git a/lib/necromancer/conversion_target.rb b/lib/necromancer/conversion_target.rb
index 0cd4180..d55d21d 100644
--- a/lib/necromancer/conversion_target.rb
+++ b/lib/necromancer/conversion_target.rb
@@ -20,12 +20,12 @@ module Necromancer
if UndefinedValue.equal?(value)
unless block
raise ArgumentError,
- 'You need to pass either argument or a block to `convert`.'
+ "You need to pass either argument or a block to `convert`."
end
new(context, block.call)
elsif block
raise ArgumentError,
- 'You cannot pass both an argument and a block to `convert`.'
+ "You cannot pass both an argument and a block to `convert`."
else
new(context, value)
end
@@ -34,7 +34,7 @@ module Necromancer
# Allows to specify conversion source type
#
# @example
- # converter.convert('1').from(:string).to(:numeric) # => 1
+ # converter.convert("1").from(:string).to(:numeric) # => 1
#
# @return [ConversionType]
#
@@ -47,10 +47,10 @@ module Necromancer
# Runs a given conversion
#
# @example
- # converter.convert('1').to(:numeric) # => 1
+ # converter.convert("1").to(:numeric) # => 1
#
# @example
- # converter.convert('1') >> Integer # => 1
+ # converter.convert("1") >> Integer # => 1
#
# @return [Object]
# the converted target type
diff --git a/lib/necromancer/conversions.rb b/lib/necromancer/conversions.rb
index f579317..b0dea9d 100644
--- a/lib/necromancer/conversions.rb
+++ b/lib/necromancer/conversions.rb
@@ -1,12 +1,13 @@
# frozen_string_literal: true
-require_relative 'configuration'
-require_relative 'converter'
-require_relative 'converters/array'
-require_relative 'converters/boolean'
-require_relative 'converters/date_time'
-require_relative 'converters/numeric'
-require_relative 'converters/range'
+require_relative "configuration"
+require_relative "converter"
+require_relative "converters/array"
+require_relative "converters/boolean"
+require_relative "converters/date_time"
+require_relative "converters/hash"
+require_relative "converters/numeric"
+require_relative "converters/range"
module Necromancer
# Represents the context used to configure various converters
@@ -14,7 +15,7 @@ module Necromancer
#
# @api public
class Conversions
- DELIMITER = '->'.freeze
+ DELIMITER = "->"
# Creates a new conversions map
#
@@ -34,6 +35,7 @@ module Necromancer
ArrayConverters.load(self)
BooleanConverters.load(self)
DateTimeConverters.load(self)
+ HashConverters.load(self)
NumericConverters.load(self)
RangeConverters.load(self)
end
@@ -76,6 +78,7 @@ module Necromancer
key = generate_key(converter)
converter = add_config(converter, @configuration)
return false if converter_map.key?(key)
+
converter_map[key] = converter
true
end
@@ -101,8 +104,8 @@ module Necromancer
# @api private
def generate_key(converter)
parts = []
- parts << (converter.source ? converter.source.to_s : 'none')
- parts << (converter.target ? converter.target.to_s : 'none')
+ parts << (converter.source ? converter.source.to_s : "none")
+ parts << (converter.target ? converter.target.to_s : "none")
parts.join(DELIMITER)
end
diff --git a/lib/necromancer/converter.rb b/lib/necromancer/converter.rb
index 238b5f7..ff771ea 100644
--- a/lib/necromancer/converter.rb
+++ b/lib/necromancer/converter.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require_relative 'configuration'
+require_relative "configuration"
module Necromancer
# Abstract converter used internally as a base for other converters
@@ -34,9 +34,9 @@ module Necromancer
# @api private
def self.create(&block)
Class.new(self) do
- define_method(:initialize) { |*a| block.call(self, *a) }
+ define_method(:initialize) { |*a| block.(self, *a) }
- define_method(:call) { |value| convert.call(value) }
+ define_method(:call) { |value| convert.(value) }
end.new
end
@@ -48,7 +48,7 @@ module Necromancer
# @api private
def raise_conversion_type(value)
raise ConversionTypeError, "'#{value}' could not be converted " \
- "from `#{source}` into `#{target}` "
+ "from `#{source}` into `#{target}`"
end
attr_accessor :source
@@ -57,7 +57,7 @@ module Necromancer
attr_accessor :convert
- protected
+ # protected
attr_reader :config
end # Converter
diff --git a/lib/necromancer/converters/array.rb b/lib/necromancer/converters/array.rb
index 79a7795..c84cd9a 100644
--- a/lib/necromancer/converters/array.rb
+++ b/lib/necromancer/converters/array.rb
@@ -1,69 +1,150 @@
# frozen_string_literal: true
-require 'set'
+require "set"
-require_relative '../converter'
+require_relative "../converter"
+require_relative "boolean"
+require_relative "numeric"
module Necromancer
# Container for Array converter classes
module ArrayConverters
+ ARRAY_MATCHER = /^(.+?(\s*(?<sep>(,|-))\s*))+/x.freeze
+
# An object that converts a String to an Array
class StringToArrayConverter < Converter
# Convert string value to array
#
# @example
- # converter.call('a, b, c') # => ['a', 'b', 'c']
+ # converter.call("a, b, c") # => ["a", "b", "c"]
#
# @example
- # converter.call('1 - 2 - 3') # => [1, 2, 3]
+ # converter.call("1 - 2 - 3") # => ["1", "2", "3"]
#
# @api public
- def call(value, options = {})
- strict = options.fetch(:strict, config.strict)
- case value.to_s
- when /^\s*?((\d+)(\s*(,|-)\s*)?)+\s*?$/
- value.to_s.split($4).map(&:to_i)
- when /^((\w)(\s*(,|-)\s*)?)+$/
- value.to_s.split($4)
+ def call(value, strict: config.strict)
+ return [] if value.to_s.empty?
+
+ if match = value.to_s.match(ARRAY_MATCHER)
+ value.to_s.split(match[:sep])
else
strict ? raise_conversion_type(value) : Array(value)
end
end
end
+ class StringToBooleanArrayConverter < Converter
+ # @example
+ # converter.call("t,f,yes,no") # => [true, false, true, false]
+ #
+ # @param [Array] value
+ # the array value to boolean
+ #
+ # @api public
+ def call(value, strict: config.strict)
+ array_converter = StringToArrayConverter.new(:string, :array)
+ array = array_converter.(value, strict: strict)
+ bool_converter = ArrayToBooleanArrayConverter.new(:array, :boolean)
+ bool_converter.(array, strict: strict)
+ end
+ end
+
+ class StringToIntegerArrayConverter < Converter
+ # @example
+ # converter.call("1,2,3") # => [1, 2, 3]
+ #
+ # @api public
+ def call(string, strict: config.strict)
+ array_converter = StringToArrayConverter.new(:string, :array)
+ array = array_converter.(string, strict: strict)
+ int_converter = ArrayToIntegerArrayConverter.new(:array, :integers)
+ int_converter.(array, strict: strict)
+ end
+ end
+
+ class StringToFloatArrayConverter < Converter
+ # @example
+ # converter.call("1,2,3") # => [1.0, 2.0, 3.0]
+ #
+ # @api public
+ def call(string, strict: config.strict)
+ array_converter = StringToArrayConverter.new(:string, :array)
+ array = array_converter.(string, strict: strict)
+ float_converter = ArrayToFloatArrayConverter.new(:array, :floats)
+ float_converter.(array, strict: strict)
+ end
+ end
+
+ class StringToNumericArrayConverter < Converter
+ # Convert string value to array with numeric values
+ #
+ # @example
+ # converter.call("1,2.0,3") # => [1, 2.0, 3]
+ #
+ # @api public
+ def call(string, strict: config.strict)
+ array_converter = StringToArrayConverter.new(:string, :array)
+ array = array_converter.(string, strict: strict)
+ num_converter = ArrayToNumericArrayConverter.new(:array, :numeric)
+ num_converter.(array, strict: strict)
+ end
+ end
+
+ class ArrayToIntegerArrayConverter < Converter
+ # @example
+ # converter.call(["1", "2", "3"]) # => [1, 2, 3]
+ #
+ # @api public
+ def call(array, strict: config.strict)
+ int_converter = NumericConverters::StringToIntegerConverter.new(:string,
+ :integer)
+ array.map { |val| int_converter.(val, strict: strict) }
+ end
+ end
+
+ class ArrayToFloatArrayConverter < Converter
+ # @example
+ # converter.call(["1", "2", "3"]) # => [1.0, 2.0, 3.0]
+ #
+ # @api public
+ def call(array, strict: config.strict)
+ float_converter = NumericConverters::StringToFloatConverter.new(:string,
+ :float)
+ array.map { |val| float_converter.(val, strict: strict) }
+ end
+ end
+
# An object that converts an array to an array with numeric values
- class ArrayToNumericConverter < Converter
+ class ArrayToNumericArrayConverter < Converter
# Convert an array to an array of numeric values
#
# @example
- # converter.call(['1', '2.3', '3.0]) # => [1, 2.3, 3.0]
+ # converter.call(["1", "2.3", "3.0]) # => [1, 2.3, 3.0]
#
# @param [Array] value
# the value to convert
#
# @api public
- def call(value, options = {})
- numeric_converter = NumericConverters::StringToNumericConverter.new(:string, :numeric)
- value.reduce([]) do |acc, el|
- acc << numeric_converter.call(el, **options)
- end
+ def call(value, strict: config.strict)
+ num_converter = NumericConverters::StringToNumericConverter.new(:string,
+ :numeric)
+ value.map { |val| num_converter.(val, strict: strict) }
end
end
# An object that converts an array to an array with boolean values
- class ArrayToBooleanConverter < Converter
+ class ArrayToBooleanArrayConverter < Converter
# @example
- # converter.call(['t', 'f', 'yes', 'no']) # => [true, false, true, false]
+ # converter.call(["t", "f", "yes", "no"]) # => [true, false, true, false]
#
# @param [Array] value
# the array value to boolean
#
# @api public
- def call(value, options = {})
- boolean_converter = BooleanConverters::StringToBooleanConverter.new(:string, :boolean)
- value.reduce([]) do |acc, el|
- acc << boolean_converter.call(el, options)
- end
+ def call(value, strict: config.strict)
+ bool_converter = BooleanConverters::StringToBooleanConverter.new(:string,
+ :boolean)
+ value.map { |val| bool_converter.(val, strict: strict) }
end
end
@@ -75,13 +156,10 @@ module Necromancer
# converter.call({x: 1}) # => [[:x, 1]]
#
# @api public
- def call(value, options = {})
- strict = options.fetch(:strict, config.strict)
- begin
- Array(value)
- rescue
- strict ? raise_conversion_type(value) : value
- end
+ def call(value, strict: config.strict)
+ Array(value)
+ rescue StandardError
+ strict ? raise_conversion_type(value) : value
end
end
@@ -96,23 +174,39 @@ module Necromancer
# the array to convert
#
# @api public
- def call(value, options = {})
- strict = options.fetch(:strict, config.strict)
- begin
- value.to_set
- rescue
- strict ? raise_conversion_type(value) : value
- end
+ def call(value, strict: config.strict)
+ value.to_set
+ rescue StandardError
+ strict ? raise_conversion_type(value) : value
end
end
def self.load(conversions)
- conversions.register NullConverter.new(:array, :array)
- conversions.register StringToArrayConverter.new(:string, :array)
- conversions.register ArrayToNumericConverter.new(:array, :numeric)
- conversions.register ArrayToBooleanConverter.new(:array, :boolean)
- conversions.register ObjectToArrayConverter.new(:object, :array)
- conversions.register ObjectToArrayConverter.new(:hash, :array)
+ [
+ NullConverter.new(:array, :array),
+
+ StringToArrayConverter.new(:string, :array),
+ StringToBooleanArrayConverter.new(:string, :bools),
+ StringToBooleanArrayConverter.new(:string, :booleans),
+ StringToIntegerArrayConverter.new(:string, :integers),
+ StringToIntegerArrayConverter.new(:string, :ints),
+ StringToFloatArrayConverter.new(:string, :floats),
+ StringToNumericArrayConverter.new(:string, :numerics),
+ StringToNumericArrayConverter.new(:string, :nums),
+
+ ArrayToNumericArrayConverter.new(:array, :numerics),
+ ArrayToNumericArrayConverter.new(:array, :nums),
+ ArrayToIntegerArrayConverter.new(:array, :integers),
+ ArrayToIntegerArrayConverter.new(:array, :ints),
+ ArrayToFloatArrayConverter.new(:array, :floats),
+ ArrayToBooleanArrayConverter.new(:array, :booleans),
+ ArrayToBooleanArrayConverter.new(:array, :bools),
+
+ ObjectToArrayConverter.new(:object, :array),
+ ObjectToArrayConverter.new(:hash, :array)
+ ].each do |converter|
+ conversions.register converter
+ end
end
end # ArrayConverters
end # Necromancer
diff --git a/lib/necromancer/converters/boolean.rb b/lib/necromancer/converters/boolean.rb
index 8385221..cbf053b 100644
--- a/lib/necromancer/converters/boolean.rb
+++ b/lib/necromancer/converters/boolean.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
-require_relative '../converter'
-require_relative '../null_converter'
+require_relative "../converter"
+require_relative "../null_converter"
module Necromancer
# Container for Boolean converter classes
@@ -29,8 +29,7 @@ module Necromancer
# 0, f, F, FALSE, false, False, n, N, NO, no, No, off, OFF
#
# @api public
- def call(value, options = {})
- strict = options.fetch(:strict, config.strict)
+ def call(value, strict: config.strict)
case value.to_s
when TRUE_MATCHER then true
when FALSE_MATCHER then false
@@ -50,13 +49,10 @@ module Necromancer
# converter.call(0) # => false
#
# @api public
- def call(value, options = {})
- strict = options.fetch(:strict, config.strict)
- begin
- !value.zero?
- rescue
- strict ? raise_conversion_type(value) : value
- end
+ def call(value, strict: config.strict)
+ !value.zero?
+ rescue StandardError
+ strict ? raise_conversion_type(value) : value
end
end
@@ -71,8 +67,7 @@ module Necromancer
# converter.call(false) # => 0
#
# @api public
- def call(value, options = {})
- strict = options.fetch(:strict, config.strict)
+ def call(value, strict: config.strict)
if %w[TrueClass FalseClass].include?(value.class.name)
value ? 1 : 0
else
@@ -82,10 +77,14 @@ module Necromancer
end
def self.load(conversions)
- conversions.register StringToBooleanConverter.new(:string, :boolean)
- conversions.register IntegerToBooleanConverter.new(:integer, :boolean)
- conversions.register BooleanToIntegerConverter.new(:boolean, :integer)
- conversions.register NullConverter.new(:boolean, :boolean)
+ [
+ StringToBooleanConverter.new(:string, :boolean),
+ IntegerToBooleanConverter.new(:integer, :boolean),
+ BooleanToIntegerConverter.new(:boolean, :integer),
+ NullConverter.new(:boolean, :boolean)
+ ].each do |converter|
+ conversions.register converter
+ end
end
end # BooleanConverters
end # Necromancer
diff --git a/lib/necromancer/converters/date_time.rb b/lib/necromancer/converters/date_time.rb
index cb3e7c1..0d9c497 100644
--- a/lib/necromancer/converters/date_time.rb
+++ b/lib/necromancer/converters/date_time.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
-require 'date'
-require 'time'
+require "date"
+require "time"
-require_relative '../converter'
-require_relative '../null_converter'
+require_relative "../converter"
+require_relative "../null_converter"
module Necromancer
# Container for Date converter classes
@@ -20,10 +20,9 @@ module Necromancer
# converter.call("12/11/2015") # => "2015-11-12"
#
# @api public
- def call(value, options = {})
- strict = options.fetch(:strict, config.strict)
+ def call(value, strict: config.strict)
Date.parse(value)
- rescue
+ rescue StandardError
strict ? raise_conversion_type(value) : value
end
end
@@ -37,10 +36,9 @@ module Necromancer
# converer.call("1-1-2015 15:12:44") # => "2015-01-01T15:12:44+00:00"
#
# @api public
- def call(value, options = {})
- strict = options.fetch(:strict, config.strict)
+ def call(value, strict: config.strict)
DateTime.parse(value)
- rescue
+ rescue StandardError
strict ? raise_conversion_type(value) : value
end
end
@@ -57,21 +55,24 @@ module Necromancer
# converter.call("12:35") # => 2015-01-04 12:35:00 +0100
#
# @api public
- def call(value, options = {})
- strict = options.fetch(:strict, config.strict)
+ def call(value, strict: config.strict)
Time.parse(value)
- rescue
+ rescue StandardError
strict ? raise_conversion_type(value) : value
end
end
def self.load(conversions)
- conversions.register StringToDateConverter.new(:string, :date)
- conversions.register NullConverter.new(:date, :date)
- conversions.register StringToDateTimeConverter.new(:string, :datetime)
- conversions.register NullConverter.new(:datetime, :datetime)
- conversions.register StringToTimeConverter.new(:string, :time)
- conversions.register NullConverter.new(:time, :time)
+ [
+ StringToDateConverter.new(:string, :date),
+ NullConverter.new(:date, :date),
+ StringToDateTimeConverter.new(:string, :datetime),
+ NullConverter.new(:datetime, :datetime),
+ StringToTimeConverter.new(:string, :time),
+ NullConverter.new(:time, :time)
+ ].each do |converter|
+ conversions.register converter
+ end
end
end # DateTimeConverters
end # Necromancer
diff --git a/lib/necromancer/converters/hash.rb b/lib/necromancer/converters/hash.rb
new file mode 100644
index 0000000..91f580f
--- /dev/null
+++ b/lib/necromancer/converters/hash.rb
@@ -0,0 +1,119 @@
+# frozen_string_literal: true
+
+require_relative "../converter"
+require_relative "boolean"
+require_relative "numeric"
+
+module Necromancer
+ module HashConverters
+ # An object that converts a String to a Hash
+ class StringToHashConverter < Converter
+ DEFAULT_CONVERSION = ->(val, *_rest) { val }
+
+ # Convert string value to hash
+ #
+ # @example
+ # converter.call("a:1 b:2 c:3")
+ # # => {a: "1", b: "2", c: "3"}
+ #
+ # @example
+ # converter.call("a=1 & b=3 & c=3")
+ # # => {a: "1", b: "2", c: "3"}
+ #
+ # @api public
+ def call(value, strict: config.strict, value_converter: DEFAULT_CONVERSION)
+ values = value.split(/\s*[& ]\s*/)
+ values.each_with_object({}) do |pair, pairs|
+ key, value = pair.split(/[=:]/, 2)
+ value_converted = value_converter.(value, strict: strict)
+ if current = pairs[key.to_sym]
+ pairs[key.to_sym] = Array(current) << value_converted
+ else
+ pairs[key.to_sym] = value_converted
+ end
+ pairs
+ end
+ end
+ end
+
+ class StringToIntegerHashConverter < Converter
+ # Convert string value to hash with integer values
+ #
+ # @example
+ # converter.call("a:1 b:2 c:3")
+ # # => {a: 1, b: 2, c: 3}
+ #
+ # @api public
+ def call(value, strict: config.strict)
+ int_converter = NumericConverters::StringToIntegerConverter.new(:string,
+ :integer)
+ hash_converter = StringToHashConverter.new(:string, :hash)
+ hash_converter.(value, strict: strict, value_converter: int_converter)
+ end
+ end
+
+ class StringToFloatHashConverter < Converter
+ # Convert string value to hash with float values
+ #
+ # @example
+ # converter.call("a:1 b:2 c:3")
+ # # => {a: 1.0, b: 2.0, c: 3.0}
+ #
+ # @api public
+ def call(value, strict: config.strict)
+ float_converter = NumericConverters::StringToFloatConverter.new(:string,
+ :float)
+ hash_converter = StringToHashConverter.new(:string, :hash)
+ hash_converter.(value, strict: strict, value_converter: float_converter)
+ end
+ end
+
+ class StringToNumericHashConverter < Converter
+ # Convert string value to hash with numeric values
+ #
+ # @example
+ # converter.call("a:1 b:2.0 c:3")
+ # # => {a: 1, b: 2.0, c: 3}
+ #
+ # @api public
+ def call(value, strict: config.strict)
+ num_converter = NumericConverters::StringToNumericConverter.new(:string,
+ :numeric)
+ hash_converter = StringToHashConverter.new(:string, :hash)
+ hash_converter.(value, strict: strict, value_converter: num_converter)
+ end
+ end
+
+ class StringToBooleanHashConverter < Converter
+ # Convert string value to hash with boolean values
+ #
+ # @example
+ # converter.call("a:yes b:no c:t")
+ # # => {a: true, b: false, c: true}
+ #
+ # @api public
+ def call(value, strict: config.strict)
+ bool_converter = BooleanConverters::StringToBooleanConverter.new(:string,
+ :boolean)
+ hash_converter = StringToHashConverter.new(:string, :hash)
+ hash_converter.(value, strict: strict, value_converter: bool_converter)
+ end
+ end
+
+ def self.load(conversions)
+ [
+ NullConverter.new(:hash, :hash),
+ StringToHashConverter.new(:string, :hash),
+ StringToIntegerHashConverter.new(:string, :int_hash),
+ StringToIntegerHashConverter.new(:string, :integer_hash),
+ StringToFloatHashConverter.new(:string, :float_hash),
+ StringToNumericHashConverter.new(:string, :num_hash),
+ StringToNumericHashConverter.new(:string, :numeric_hash),
+ StringToBooleanHashConverter.new(:string, :boolean_hash),
+ StringToBooleanHashConverter.new(:string, :bool_hash)
+ ].each do |converter|
+ conversions.register(converter)
+ end
+ end
+ end # HashConverters
+end # Necromancer
diff --git a/lib/necromancer/converters/numeric.rb b/lib/necromancer/converters/numeric.rb
index d45f8c0..a8b3343 100644
--- a/lib/necromancer/converters/numeric.rb
+++ b/lib/necromancer/converters/numeric.rb
@@ -1,27 +1,26 @@
# frozen_string_literal: true
-require_relative '../converter'
-require_relative '../null_converter'
+require_relative "../converter"
+require_relative "../null_converter"
module Necromancer
# Container for Numeric converter classes
module NumericConverters
- INTEGER_MATCHER = /^[-+]?(\d+)$/.freeze
+ INTEGER_MATCHER = /^\s*[-+]?\s*(\d[\d\s]*)?$/.freeze
- FLOAT_MATCHER = /^[-+]?(\d*)(\.\d+)?([eE]?[-+]?\d+)?$/.freeze
+ FLOAT_MATCHER = /^\s*[-+]?([\d\s]*)(\.[\d\s]+)?([eE]?[-+]?[\d\s]+)?$/.freeze
# An object that converts a String to an Integer
class StringToIntegerConverter < Converter
# Convert string value to integer
#
# @example
- # converter.call('1abc') # => 1
+ # converter.call("1abc") # => 1
#
# @api public
- def call(value, **options)
- strict = options.fetch(:strict, config.strict)
+ def call(value, strict: config.strict)
Integer(value)
- rescue
+ rescue StandardError
strict ? raise_conversion_type(value) : value.to_i
end
end
@@ -31,7 +30,7 @@ module Necromancer
# Convert integer value to string
#
# @example
- # converter.call(1) # => '1'
+ # converter.call(1) # => "1"
#
# @api public
def call(value, **_)
@@ -44,13 +43,12 @@ module Necromancer
# Convert string to float value
#
# @example
- # converter.call('1.2') # => 1.2
+ # converter.call("1.2") # => 1.2
#
# @api public
- def call(value, **options)
- strict = options.fetch(:strict, config.strict)
+ def call(value, strict: config.strict)
Float(value)
- rescue
+ rescue StandardError
strict ? raise_conversion_type(value) : value.to_f
end
end
@@ -60,19 +58,18 @@ module Necromancer
# Convert string to numeric value
#
# @example
- # converter.call('1.0') # => 1.0
+ # converter.call("1.0") # => 1.0
#
# @example
- # converter.call('1') # => 1
+ # converter.call("1") # => 1
#
# @api public
- def call(value, **options)
- strict = options.fetch(:strict, config.strict)
+ def call(value, strict: config.strict)
case value
when INTEGER_MATCHER
- StringToIntegerConverter.new(:string, :integer).call(value, **options)
+ StringToIntegerConverter.new(:string, :integer).(value, strict: strict)
when FLOAT_MATCHER
- StringToFloatConverter.new(:string, :float).call(value, **options)
+ StringToFloatConverter.new(:string, :float).(value, strict: strict)
else
strict ? raise_conversion_type(value) : value
end
@@ -80,12 +77,16 @@ module Necromancer
end
def self.load(conversions)
- conversions.register StringToIntegerConverter.new(:string, :integer)
- conversions.register IntegerToStringConverter.new(:integer, :string)
- conversions.register NullConverter.new(:integer, :integer)
- conversions.register StringToFloatConverter.new(:string, :float)
- conversions.register NullConverter.new(:float, :float)
- conversions.register StringToNumericConverter.new(:string, :numeric)
+ [
+ StringToIntegerConverter.new(:string, :integer),
+ IntegerToStringConverter.new(:integer, :string),
+ NullConverter.new(:integer, :integer),
+ StringToFloatConverter.new(:string, :float),
+ NullConverter.new(:float, :float),
+ StringToNumericConverter.new(:string, :numeric)
+ ].each do |converter|
+ conversions.register converter
+ end
end
end # Conversion
end # Necromancer
diff --git a/lib/necromancer/converters/range.rb b/lib/necromancer/converters/range.rb
index 4018c05..00e412c 100644
--- a/lib/necromancer/converters/range.rb
+++ b/lib/necromancer/converters/range.rb
@@ -1,16 +1,22 @@
# frozen_string_literal: true
-require_relative '../converter'
-require_relative '../null_converter'
+require_relative "../converter"
+require_relative "../null_converter"
module Necromancer
# Container for Range converter classes
module RangeConverters
- SINGLE_DIGIT_MATCHER = /^(\-?\d+)$/.freeze
+ SINGLE_DIGIT_MATCHER = /^(?<digit>-?\d+(\.\d+)?)$/.freeze
- DIGIT_MATCHER = /^(-?\d+?)(\.{2}\.?|-|,)(-?\d+)$/.freeze
+ DIGIT_MATCHER = /^(?<open>-?\d+(\.\d+)?)
+ \s*(?<sep>(\.\s*){2,3}|-|,)\s*
+ (?<close>-?\d+(\.\d+)?)$
+ /x.freeze
- LETTER_MATCHER = /^(\w)(\.{2}\.?|-|,)(\w)$/.freeze
+ LETTER_MATCHER = /^(?<open>\w)
+ \s*(?<sep>(\.\s*){2,3}|-|,)\s*
+ (?<close>\w)$
+ /x.freeze
# An object that converts a String to a Range
class StringToRangeConverter < Converter
@@ -19,30 +25,47 @@ module Necromancer
# @param [Object] value
#
# @example
- # converter.call('0,9') # => (0..9)
+ # converter.call("0,9") # => (0..9)
#
# @example
- # converter.call('0-9') # => (0..9)
+ # converter.call("0-9") # => (0..9)
#
# @api public
- def call(value, options = {})
- strict = options.fetch(:strict, config.strict)
- case value
- when SINGLE_DIGIT_MATCHER
- ::Range.new($1.to_i, $1.to_i)
- when DIGIT_MATCHER
- ::Range.new($1.to_i, $3.to_i, $2 == '...')
- when LETTER_MATCHER
- ::Range.new($1.to_s, $3.to_s, $2 == '...')
+ def call(value, strict: config.strict)
+ if match = value.match(SINGLE_DIGIT_MATCHER)
+ digit = cast_to_num(match[:digit])
+ ::Range.new(digit, digit)
+ elsif match = value.match(DIGIT_MATCHER)
+ open = cast_to_num(match[:open])
+ close = cast_to_num(match[:close])
+ ::Range.new(open, close, match[:sep].gsub(/\s*/, "") == "...")
+ elsif match = value.match(LETTER_MATCHER)
+ ::Range.new(match[:open], match[:close],
+ match[:sep].gsub(/\s*/, "") == "...")
else
strict ? raise_conversion_type(value) : value
end
end
+
+ # Convert range end to numeric value
+ #
+ # @api private
+ def cast_to_num(str)
+ Integer(str)
+ rescue ArgumentError
+ Float(str)
+ rescue ArgumentError
+ nil
+ end
end
def self.load(conversions)
- conversions.register StringToRangeConverter.new(:string, :range)
- conversions.register NullConverter.new(:range, :range)
+ [
+ StringToRangeConverter.new(:string, :range),
+ NullConverter.new(:range, :range)
+ ].each do |converter|
+ conversions.register converter
+ end
end
end # RangeConverters
end # Necromancer
diff --git a/lib/necromancer/null_converter.rb b/lib/necromancer/null_converter.rb
index f605025..4a2856a 100644
--- a/lib/necromancer/null_converter.rb
+++ b/lib/necromancer/null_converter.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-require_relative 'converter'
+require_relative "converter"
module Necromancer
# A pass through converter
class NullConverter < Converter
- def call(value, **options)
+ def call(value, strict: config.strict)
value
end
end # NullConverter
diff --git a/lib/necromancer/version.rb b/lib/necromancer/version.rb
index d0edae5..9081a44 100644
--- a/lib/necromancer/version.rb
+++ b/lib/necromancer/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module Necromancer
- VERSION = "0.5.1"
+ VERSION = "0.7.0"
end # Necromancer
diff --git a/necromancer.gemspec b/necromancer.gemspec
index b954049..7ac136f 100644
--- a/necromancer.gemspec
+++ b/necromancer.gemspec
@@ -1,17 +1,16 @@
-lib = File.expand_path('../lib', __FILE__)
-$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
-require 'necromancer/version'
+# frozen_string_literal: true
+
+require_relative "lib/necromancer/version"
Gem::Specification.new do |spec|
- spec.name = 'necromancer'
+ spec.name = "necromancer"
spec.version = Necromancer::VERSION
- spec.authors = ['Piotr Murach']
- spec.email = ['me@piotrmurach.com']
+ spec.authors = ["Piotr Murach"]
+ spec.email = ["piotr@piotrmurach.com"]
spec.summary = %q{Conversion from one object type to another with a bit of black magic.}
spec.description = %q{Conversion from one object type to another with a bit of black magic.}
- spec.homepage = 'https://github.com/piotrmurach/necromancer'
- spec.license = 'MIT'
-
+ spec.homepage = "https://github.com/piotrmurach/necromancer"
+ spec.license = "MIT"
if spec.respond_to?(:metadata=)
spec.metadata["allowed_push_host"] = "https://rubygems.org"
spec.metadata["changelog_uri"] = "https://github.com/piotrmurach/necromancer/blob/master/CHANGELOG.md"
@@ -19,16 +18,11 @@ Gem::Specification.new do |spec|
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = "https://github.com/piotrmurach/necromancer"
end
-
- spec.files = Dir['{lib,spec}/**/*.rb']
- spec.files += Dir['tasks/*', 'necromancer.gemspec']
- spec.files += Dir['README.md', 'CHANGELOG.md', 'LICENSE.txt', 'Rakefile']
- spec.test_files = spec.files.grep(%r{^(spec)/})
+ spec.files = Dir["lib/**/*"]
+ spec.extra_rdoc_files = ["README.md", "CHANGELOG.md", "LICENSE.txt"]
spec.require_paths = ["lib"]
+ spec.required_ruby_version = ">= 2.0.0"
- spec.required_ruby_version = '>= 2.0.0'
-
- spec.add_development_dependency 'bundler', '>= 1.6'
- spec.add_development_dependency 'rake'
- spec.add_development_dependency 'rspec', '~> 3.0'
+ spec.add_development_dependency "rake"
+ spec.add_development_dependency "rspec", ">= 3.0"
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 9479672..1161d98 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
-if ENV['COVERAGE'] || ENV['TRAVIS']
- require 'simplecov'
- require 'coveralls'
+if ENV["COVERAGE"] == "true"
+ require "simplecov"
+ require "coveralls"
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
SimpleCov::Formatter::HTMLFormatter,
@@ -10,16 +10,17 @@ if ENV['COVERAGE'] || ENV['TRAVIS']
])
SimpleCov.start do
- command_name 'spec'
- add_filter 'spec'
+ command_name "spec"
+ add_filter "spec"
end
end
-require 'necromancer'
+require "necromancer"
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+ expectations.max_formatted_output_length = nil
end
config.mock_with :rspec do |mocks|
@@ -34,7 +35,7 @@ RSpec.configure do |config|
config.warnings = true
if config.files_to_run.one?
- config.default_formatter = 'doc'
+ config.default_formatter = "doc"
end
config.profile_examples = 2
@@ -42,12 +43,4 @@ RSpec.configure do |config|
config.order = :random
Kernel.srand config.seed
-
- config.before :each do
- [:UpcaseConverter, :Custom].each do |class_name|
- if Object.const_defined?(class_name)
- Object.send(:remove_const, class_name)
- end
- end
- end
end
diff --git a/spec/unit/can_spec.rb b/spec/unit/can_spec.rb
index d141f9f..31f7116 100644
--- a/spec/unit/can_spec.rb
+++ b/spec/unit/can_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe Necromancer, 'can?' do
+RSpec.describe Necromancer, "can?" do
it "checks if conversion is possible" do
converter = described_class.new
expect(converter.can?(:string, :integer)).to eq(true)
diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb
index 9973b47..ef33160 100644
--- a/spec/unit/config_spec.rb
+++ b/spec/unit/config_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe Necromancer, 'config' do
+RSpec.describe Necromancer, "config" do
it "configures global settings per instance" do
converter = described_class.new
diff --git a/spec/unit/configuration/new_spec.rb b/spec/unit/configuration/new_spec.rb
index c84c5a9..2706710 100644
--- a/spec/unit/configuration/new_spec.rb
+++ b/spec/unit/configuration/new_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
-RSpec.describe Necromancer::Configuration, '.new' do
-
+RSpec.describe Necromancer::Configuration, ".new" do
subject(:config) { described_class.new }
it { is_expected.to respond_to(:strict=) }
diff --git a/spec/unit/conversions/fetch_spec.rb b/spec/unit/conversions/fetch_spec.rb
index 4431d53..96307cf 100644
--- a/spec/unit/conversions/fetch_spec.rb
+++ b/spec/unit/conversions/fetch_spec.rb
@@ -1,16 +1,16 @@
# frozen_string_literal: true
-RSpec.describe Necromancer::Conversions, '#fetch' do
+RSpec.describe Necromancer::Conversions, "#fetch" do
it "retrieves conversion given source & target" do
converter = double(:converter)
- conversions = described_class.new nil, {'string->array' => converter}
- expect(conversions['string', 'array']).to eq(converter)
+ conversions = described_class.new nil, { "string->array" => converter }
+ expect(conversions["string", "array"]).to eq(converter)
end
it "fails to find conversion" do
conversions = described_class.new
expect {
- conversions['string', 'array']
+ conversions["string", "array"]
}.to raise_error(Necromancer::NoTypeConversionAvailableError)
end
end
diff --git a/spec/unit/conversions/register_spec.rb b/spec/unit/conversions/register_spec.rb
index a7a4466..5ccfb48 100644
--- a/spec/unit/conversions/register_spec.rb
+++ b/spec/unit/conversions/register_spec.rb
@@ -1,23 +1,23 @@
# frozen_string_literal: true
-RSpec.describe Necromancer::Conversions, '.register' do
+RSpec.describe Necromancer::Conversions, ".register" do
it "allows to register converter" do
context = described_class.new
- converter = double(:converter, {source: :string, target: :numeric})
+ converter = double(:converter, { source: :string, target: :numeric })
expect(context.register(converter)).to eq(true)
expect(context[:string, :numeric]).to eq(converter)
end
it "allows to register converter with no source" do
context = described_class.new
- converter = double(:converter, {source: nil, target: :numeric})
+ converter = double(:converter, { source: nil, target: :numeric })
expect(context.register(converter)).to eq(true)
expect(context[:none, :numeric]).to eq(converter)
end
it "allows to register converter with no target" do
context = described_class.new
- converter = double(:converter, {source: :string, target: nil})
+ converter = double(:converter, { source: :string, target: nil })
expect(context.register(converter)).to eq(true)
expect(context[:string, :none]).to eq(converter)
end
@@ -26,33 +26,33 @@ RSpec.describe Necromancer::Conversions, '.register' do
conversions = described_class.new
conversions.register do |c|
- c.source= :string
- c.target= :upcase
- c.convert = proc { |value| value.to_s.upcase }
+ c.source = :string
+ c.target = :upcase
+ c.convert = ->(value) { value.to_s.upcase }
end
- expect(conversions[:string, :upcase].call('magic')).to eq('MAGIC')
+ expect(conversions[:string, :upcase].("magic")).to eq("MAGIC")
end
it "allows to register anonymous converter with class names" do
conversions = described_class.new
conversions.register do |c|
- c.source= String
- c.target= Array
- c.convert = proc { |value| Array(value) }
+ c.source = String
+ c.target = Array
+ c.convert = ->(value) { Array(value) }
end
- expect(conversions[String, Array].call('magic')).to eq(['magic'])
+ expect(conversions[String, Array].("magic")).to eq(["magic"])
end
it "allows to register custom converter" do
conversions = described_class.new
- UpcaseConverter = Struct.new(:source, :target) do
+ stub_const("UpcaseConverter", Struct.new(:source, :target) do
def call(value)
value.to_s.upcase
end
- end
+ end)
upcase_converter = UpcaseConverter.new(:string, :upcase)
expect(conversions.register(upcase_converter)).to be(true)
- expect(conversions[:string, :upcase].call('magic')).to eq('MAGIC')
+ expect(conversions[:string, :upcase].("magic")).to eq("MAGIC")
end
end
diff --git a/spec/unit/conversions/to_hash_spec.rb b/spec/unit/conversions/to_hash_spec.rb
index 89808e7..8e8ec4e 100644
--- a/spec/unit/conversions/to_hash_spec.rb
+++ b/spec/unit/conversions/to_hash_spec.rb
@@ -1,37 +1,58 @@
# frozen_string_literal: true
-RSpec.describe Necromancer::Conversions, '#to_hash' do
- it 'exports default conversions to hash' do
+RSpec.describe Necromancer::Conversions, "#to_hash" do
+ it "exports default conversions to hash" do
conversions = Necromancer::Conversions.new
expect(conversions.to_hash).to eq({})
conversions.load
expect(conversions.to_hash.keys.sort).to eq([
- 'array->array',
- 'array->boolean',
- 'array->numeric',
- 'boolean->boolean',
- 'boolean->integer',
- 'date->date',
- 'datetime->datetime',
- 'float->float',
- 'hash->array',
- 'integer->boolean',
- 'integer->integer',
- 'integer->string',
- 'object->array',
- 'range->range',
- 'string->array',
- 'string->boolean',
- 'string->date',
- 'string->datetime',
- 'string->float',
- 'string->integer',
- 'string->numeric',
- 'string->range',
- 'string->time',
- 'time->time'
+ "array->array",
+ "array->booleans",
+ "array->bools",
+ "array->floats",
+ "array->integers",
+ "array->ints",
+ "array->numerics",
+ "array->nums",
+ "boolean->boolean",
+ "boolean->integer",
+ "date->date",
+ "datetime->datetime",
+ "float->float",
+ "hash->array",
+ "hash->hash",
+ "integer->boolean",
+ "integer->integer",
+ "integer->string",
+ "object->array",
+ "range->range",
+ "string->array",
+ "string->bool_hash",
+ "string->boolean",
+ "string->boolean_hash",
+ "string->booleans",
+ "string->bools",
+ "string->date",
+ "string->datetime",
+ "string->float",
+ "string->float_hash",
+ "string->floats",
+ "string->hash",
+ "string->int_hash",
+ "string->integer",
+ "string->integer_hash",
+ "string->integers",
+ "string->ints",
+ "string->num_hash",
+ "string->numeric",
+ "string->numeric_hash",
+ "string->numerics",
+ "string->nums",
+ "string->range",
+ "string->time",
+ "time->time"
])
end
end
diff --git a/spec/unit/convert_spec.rb b/spec/unit/convert_spec.rb
index f26bf6c..2a402f1 100644
--- a/spec/unit/convert_spec.rb
+++ b/spec/unit/convert_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
-RSpec.describe Necromancer, '.convert' do
-
+RSpec.describe Necromancer, ".convert" do
subject(:converter) { described_class.new }
it "indicates inability to perform the requested conversion" do
@@ -12,56 +11,112 @@ RSpec.describe Necromancer, '.convert' do
end
it "allows for module level convert call" do
- expect(Necromancer.convert('1,2,3').to(:array)).to eq([1,2,3])
+ expect(Necromancer.convert("1,2,3").to(:array)).to eq(%w[1 2 3])
end
it "allows replacing #to with #>> call" do
- expect(converter.convert('1,2,3') >> :array).to eq([1,2,3])
+ expect(converter.convert("1,2,3") >> :integers).to eq([1, 2, 3])
end
it "allows to specify object as conversion target" do
- expect(converter.convert('1,2,3') >> []).to eq([1,2,3])
+ expect(converter.convert("1,2,3") >> []).to eq(%w[1 2 3])
end
it "allows to specify class as conversion target" do
- expect(converter.convert('1,2,3') >> Array).to eq([1,2,3])
+ expect(converter.convert("1,2,3") >> Array).to eq(%w[1 2 3])
end
- context 'when array' do
+ context "when array" do
it "converts string to array" do
- expect(converter.convert("1,2,3").to(:array)).to eq([1,2,3])
+ expect(converter.convert("1,2,3").to(:array)).to eq(%w[1 2 3])
+ end
+
+ it "converts string to array of booleans" do
+ expect(converter.convert("t,f,t").to(:booleans)).to eq([true, false, true])
+ expect(converter.convert("t,f,t").to(:bools)).to eq([true, false, true])
end
- it "converts array to numeric " do
- expect(converter.convert(['1','2.3','3.0']).to(:numeric)).to eq([1,2.3,3.0])
+ it "converts string to array of integers" do
+ expect(converter.convert("1,2,3").to(:integers)).to eq([1, 2, 3])
+ expect(converter.convert("1,2,3").to(:ints)).to eq([1, 2, 3])
end
- it "converts array to boolean" do
- expect(converter.convert(['t', 'no']).to(:boolean)).to eq([true, false])
+ it "converts string to array of numerics" do
+ expect(converter.convert("1,2.0,3").to(:numerics)).to eq([1, 2.0, 3])
+ expect(converter.convert("1,2.0,3").to(:nums)).to eq([1, 2.0, 3])
+ end
+
+ it "converts array to numerics " do
+ conversion = converter.convert(["1", "2.3", "3.0"]).to(:numerics)
+ expect(conversion).to eq([1, 2.3, 3.0])
+ conversion = converter.convert(["1", "2.3", "3.0"]).to(:nums)
+ expect(conversion).to eq([1, 2.3, 3.0])
+ end
+
+ it "converts array to array of booleans" do
+ expect(converter.convert(%w[t no]).to(:booleans)).to eq([true, false])
+ expect(converter.convert(%w[t no]).to(:bools)).to eq([true, false])
end
it "converts object to array" do
- expect(converter.convert({x: 1}).to(:array)).to eq([[:x, 1]])
+ expect(converter.convert({ x: 1 }).to(:array)).to eq([[:x, 1]])
end
it "fails to convert in strict mode" do
expect {
- converter.convert(['1', '2.3', false]).to(:numeric, strict: true)
+ converter.convert(["1", "2.3", false]).to(:numerics, strict: true)
}.to raise_error(Necromancer::ConversionTypeError)
end
end
- context 'when numeric' do
+ context "when hash" do
+ it "converts hash to hash" do
+ conversion = converter.convert({ a: 1, b: 2, c: 3 }).to(:hash)
+ expect(conversion).to eq({ a: 1, b: 2, c: 3 })
+ end
+
+ it "converts string to hash" do
+ conversion = converter.convert("a:1 b:2 c:3").to(:hash)
+ expect(conversion).to eq({ a: "1", b: "2", c: "3" })
+ end
+
+ it "converts string to integer hash" do
+ conversion = converter.convert("a:1 b:2 c:3").to(:int_hash)
+ expect(conversion).to eq({ a: 1, b: 2, c: 3 })
+ end
+
+ it "converts string to float hash" do
+ conversion = converter.convert("a:1 b:2 c:3").to(:float_hash)
+ expect(conversion).to eq({ a: 1.0, b: 2.0, c: 3.0 })
+ end
+
+ it "converts string to numeric hash" do
+ conversion = converter.convert("a:1 b:2.0 c:3").to(:numeric_hash)
+ expect(conversion).to eq({ a: 1, b: 2.0, c: 3 })
+ end
+
+ it "converts string to boolean hash" do
+ conversion = converter.convert("a:t b:f c:t").to(:boolean_hash)
+ expect(conversion).to eq({ a: true, b: false, c: true })
+ end
+
+ it "converts string to bool hash" do
+ conversion = converter.convert("a:t b:f c:t").to(:bool_hash)
+ expect(conversion).to eq({ a: true, b: false, c: true })
+ end
+ end
+
+ context "when numeric" do
it "converts string to integer" do
- expect(converter.convert('1').to(:integer)).to eq(1)
+ expect(converter.convert("1").to(:integer)).to eq(1)
end
it "allows for block for conversion method" do
- expect(converter.convert { '1' }.to(:integer)).to eq(1)
+ expect(converter.convert { "1" }.to(:integer)).to eq(1)
end
it "convers integer to string" do
- expect(converter.convert(1).to(:string)).to eq('1')
+ expect(converter.convert(1).to(:string)).to eq("1")
end
it "allows for null type conversion" do
@@ -70,30 +125,30 @@ RSpec.describe Necromancer, '.convert' do
it "raises error when in strict mode" do
expect {
- converter.convert('1a').to(:integer, strict: true)
+ converter.convert("1a").to(:integer, strict: true)
}.to raise_error(Necromancer::ConversionTypeError)
end
it "doesn't raise error when in non-strict mode" do
- expect(converter.convert('1').to(:integer, strict: false)).to eql(1)
+ expect(converter.convert("1").to(:integer, strict: false)).to eql(1)
end
it "converts string to float" do
- expect(converter.convert('1.0').to(:float)).to eql(1.0)
+ expect(converter.convert("1.0").to(:float)).to eql(1.0)
end
it "converts string to numeric" do
- expect(converter.convert('1.0').to(:numeric)).to eql(1.0)
+ expect(converter.convert("1.0").to(:numeric)).to eql(1.0)
end
end
- context 'when boolean' do
+ context "when boolean" do
it "converts boolean to boolean" do
expect(converter.convert(true).to(:boolean)).to eq(true)
end
it "converts string to boolean" do
- expect(converter.convert('yes').to(:boolean)).to eq(true)
+ expect(converter.convert("yes").to(:boolean)).to eq(true)
end
it "converts integer to boolean" do
@@ -105,26 +160,26 @@ RSpec.describe Necromancer, '.convert' do
end
end
- context 'when range' do
+ context "when range" do
it "converts string to range" do
- expect(converter.convert('1-10').to(:range)).to eq(1..10)
+ expect(converter.convert("1-10").to(:range)).to eq(1..10)
end
end
- context 'when datetime' do
+ context "when datetime" do
it "converts string to date" do
- expect(converter.convert('2014-12-07').to(:date)).
- to eq(Date.parse('2014-12-07'))
+ expect(converter.convert("2014-12-07").to(:date))
+ .to eq(Date.parse("2014-12-07"))
end
it "converts string to datetime" do
- expect(converter.convert('2014-12-07 17:35:44').to(:datetime)).
- to eq(DateTime.parse('2014-12-07 17:35:44'))
+ expect(converter.convert("2014-12-07 17:35:44").to(:datetime))
+ .to eq(DateTime.parse("2014-12-07 17:35:44"))
end
it "converts string to time" do
- expect(converter.convert('12:30').to(:time)).
- to eq(Time.parse('12:30'))
+ expect(converter.convert("12:30").to(:time))
+ .to eq(Time.parse("12:30"))
end
end
end
diff --git a/spec/unit/converters/array/array_to_boolean_spec.rb b/spec/unit/converters/array/array_to_boolean_spec.rb
deleted file mode 100644
index 30d8f5f..0000000
--- a/spec/unit/converters/array/array_to_boolean_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::ArrayConverters::ArrayToBooleanConverter, '.call' do
-
- subject(:converter) { described_class.new(:array, :boolean) }
-
- it "converts `['t', 'f', 'yes', 'no']` to boolean array" do
- expect(converter.call(['t', 'f', 'yes', 'no'])).to eq([true, false, true, false])
- end
-
- it "fails to convert `['t', 'no', 5]` to boolean array in strict mode" do
- expect {
- converter.call(['t', 'no', 5], strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-
- it "converts `['t', 'no', 5]` to boolean array in non-strict mode" do
- expect(converter.call(['t', 'no', 5], strict: false)).to eql([true, false, 5])
- end
-end
diff --git a/spec/unit/converters/array/array_to_numeric_spec.rb b/spec/unit/converters/array/array_to_numeric_spec.rb
deleted file mode 100644
index 3ba1fab..0000000
--- a/spec/unit/converters/array/array_to_numeric_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::ArrayConverters::ArrayToNumericConverter, '.call' do
-
- subject(:converter) { described_class.new(:array, :numeric) }
-
- it "converts `['1','2.3','3.0']` to numeric array" do
- expect(converter.call(['1', '2.3', '3.0'])).to eq([1, 2.3, 3.0])
- end
-
- it "fails to convert `['1','2.3',false]` to numeric array in strict mode" do
- expect {
- converter.call(['1', '2.3', false], strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-
- it "converts `['1','2.3',false]` to numeric array in non-strict mode" do
- expect(converter.call(['1', '2.3', false], strict: false)).to eq([1, 2.3, false])
- end
-end
diff --git a/spec/unit/converters/array/array_to_set_spec.rb b/spec/unit/converters/array/array_to_set_spec.rb
deleted file mode 100644
index 7189e39..0000000
--- a/spec/unit/converters/array/array_to_set_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::ArrayConverters::ArrayToSetConverter, '.call' do
-
- subject(:converter) { described_class.new(:array, :set) }
-
- it "converts `[:x,:y,:x,1,2,1]` to set" do
- expect(converter.call([:x,:y,:x,1,2,1])).to eql(Set[:x,:y,1,2])
- end
-
- it "fails to convert `1` to set" do
- expect {
- converter.call(1, strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-end
diff --git a/spec/unit/converters/array/object_to_array_spec.rb b/spec/unit/converters/array/object_to_array_spec.rb
deleted file mode 100644
index 3cf3aea..0000000
--- a/spec/unit/converters/array/object_to_array_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::ArrayConverters::ObjectToArrayConverter, '.call' do
- subject(:converter) { described_class.new(:object, :array) }
-
- it "converts nil to array" do
- expect(converter.call(nil)).to eq([])
- end
-
- it "converts custom object to array" do
- Custom = Class.new do
- def to_ary
- [:x, :y]
- end
- end
- custom = Custom.new
- expect(converter.call(custom)).to eq([:x, :y])
- end
-end
diff --git a/spec/unit/converters/array/string_to_array_spec.rb b/spec/unit/converters/array/string_to_array_spec.rb
deleted file mode 100644
index 9e2febb..0000000
--- a/spec/unit/converters/array/string_to_array_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::ArrayConverters::StringToArrayConverter, '.call' do
- subject(:converter) { described_class.new(:string, :array) }
-
- it "converts empty string to array" do
- expect(converter.call('', strict: false)).to eq([''])
- end
-
- it "fails to convert empty string to array in strict mode" do
- expect {
- converter.call('', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-
- it "converts `1,2,3` to array" do
- expect(converter.call('1,2,3')).to eq([1,2,3])
- end
-
- it "converts `a,b,c` to array" do
- expect(converter.call('a,b,c')).to eq(['a','b','c'])
- end
-
- it "converts '1-2-3' to array" do
- expect(converter.call('1-2-3')).to eq([1,2,3])
- end
-
- it "converts ' 1 - 2 - 3 ' to array" do
- expect(converter.call(' 1 - 2 - 3 ')).to eq([1,2,3])
- end
-end
diff --git a/spec/unit/converters/array_spec.rb b/spec/unit/converters/array_spec.rb
new file mode 100644
index 0000000..f0f36ea
--- /dev/null
+++ b/spec/unit/converters/array_spec.rb
@@ -0,0 +1,252 @@
+# frozen_string_literal: true
+
+RSpec.describe Necromancer::ArrayConverters, "#call" do
+ describe ":string -> :array" do
+ subject(:converter) {
+ described_class::StringToArrayConverter.new(:string, :array)
+ }
+
+ {
+ "" => [],
+ "123" => %w[123],
+ "1,2,3" => %w[1 2 3],
+ "1-2-3" => %w[1 2 3],
+ " 1 - 2 - 3 " => [" 1 ", " 2 ", " 3 "],
+ "1 , 2 , 3" => ["1 ", " 2 ", " 3"],
+ "1.2,2.3,3.4" => %w[1.2 2.3 3.4],
+ "a,b,c" => %w[a b c],
+ "a-b-c" => %w[a b c],
+ "aa a,b bb,c c c" => %w[aa\ a b\ bb c\ c\ c]
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+
+ it "fails to convert empty string to array in strict mode" do
+ expect {
+ converter.("unknown", strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'unknown' could not be converted from `string` into `array`"
+ )
+ end
+ end
+
+ describe ":string -> :booleans" do
+ subject(:converter) { described_class::StringToBooleanArrayConverter.new }
+
+ {
+ "t,f,t" => [true, false, true],
+ "yes,no,Y" => [true, false, true],
+ "1-0-FALSE" => [true, false, false]
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+
+ it "fails to convert in strict mode" do
+ expect {
+ converter.("yes,unknown", strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'unknown' could not be converted from `string` into `boolean`"
+ )
+ end
+ end
+
+ describe ":string -> :integers/:ints" do
+ subject(:converter) { described_class::StringToIntegerArrayConverter.new }
+
+ {
+ "1,2,3" => [1, 2, 3],
+ "1.2, 2.3, 3.4" => [1, 2, 3]
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+
+ it "fails to convert in strict mode" do
+ expect {
+ converter.("1,unknown", strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'unknown' could not be converted from `string` into `integer`"
+ )
+ end
+ end
+
+ describe ":string -> :floats" do
+ subject(:converter) { described_class::StringToFloatArrayConverter.new }
+
+ {
+ "1,2,3" => [1.0, 2.0, 3.0],
+ "1.2, 2.3, 3.4" => [1.2, 2.3, 3.4]
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+
+ it "fails to convert in strict mode" do
+ expect {
+ converter.("1,unknown", strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'unknown' could not be converted from `string` into `float`"
+ )
+ end
+ end
+
+ describe ":string -> :numerics/:nums" do
+ subject(:converter) { described_class::StringToNumericArrayConverter.new }
+
+ {
+ "1,2.0,3" => [1, 2.0, 3],
+ "1.2, 2.3, 3.4" => [1.2, 2.3, 3.4]
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+
+ it "fails to convert in strict mode" do
+ expect {
+ converter.("1,unknown", strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'unknown' could not be converted from `string` into `numeric`"
+ )
+ end
+ end
+
+ describe ":array -> :booleans/:bools" do
+ subject(:converter) {
+ described_class::ArrayToBooleanArrayConverter.new(:array, :boolean)
+ }
+
+ {
+ %w[t f yes no] => [true, false, true, false],
+ %w[t no 5] => [true, false, "5"]
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+
+ it "fails to convert `['t', 'no', 5]` to boolean array in strict mode" do
+ expect {
+ converter.(["t", "no", 5], strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'5' could not be converted from `string` into `boolean`"
+ )
+ end
+ end
+
+ describe ":array -> :integers" do
+ subject(:converter) { described_class::ArrayToIntegerArrayConverter.new }
+
+ {
+ %w[1 2 3] => [1, 2, 3],
+ %w[1.2 2.3 3.4] => [1, 2, 3]
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+
+ it "fails to convert `['1','2.3']` to integer array in strict mode" do
+ expect {
+ converter.(["1", "2.3"], strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'2.3' could not be converted from `string` into `integer`"
+ )
+ end
+ end
+
+ describe ":array -> :floats" do
+ subject(:converter) { described_class::ArrayToFloatArrayConverter.new }
+
+ {
+ %w[1 2 3] => [1.0, 2.0, 3.0],
+ %w[1.2 2.3 3.4] => [1.2, 2.3, 3.4]
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+
+ it "fails to convert `['1','2.3',false]` to float array in strict mode" do
+ expect {
+ converter.(["1", "2.3", false], strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'false' could not be converted from `string` into `float`"
+ )
+ end
+ end
+
+ describe ":array -> :numerics/:nums" do
+ subject(:converter) {
+ described_class::ArrayToNumericArrayConverter.new(:array, :numerics)
+ }
+
+ {
+ %w[1 2.3 3.0] => [1, 2.3, 3.0],
+ %w[1 2.3 false] => [1, 2.3, "false"]
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+
+ it "fails to convert `['1','2.3',false]` to numeric array in strict mode" do
+ expect {
+ converter.(["1", "2.3", false], strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'false' could not be converted from `string` into `numeric`"
+ )
+ end
+ end
+
+ describe ":array -> :set" do
+ subject(:converter) {
+ described_class::ArrayToSetConverter.new(:array, :set)
+ }
+
+ it "converts `[:x,:y,:x,1,2,1]` to set" do
+ expect(converter.([:x, :y, :x, 1, 2, 1])).to eql(Set[:x, :y, 1, 2])
+ end
+
+ it "fails to convert `1` to set" do
+ expect {
+ converter.(1, strict: true)
+ }.to raise_error(Necromancer::ConversionTypeError)
+ end
+ end
+
+ describe ":object -> :array" do
+ subject(:converter) {
+ described_class::ObjectToArrayConverter.new(:object, :array)
+ }
+
+ it "converts nil to array" do
+ expect(converter.(nil)).to eq([])
+ end
+
+ it "converts custom object to array" do
+ stub_const("Custom", Class.new do
+ def to_ary
+ %i[x y]
+ end
+ end)
+ custom = Custom.new
+ expect(converter.(custom)).to eq(%i[x y])
+ end
+ end
+end
diff --git a/spec/unit/converters/boolean/boolean_to_integer_spec.rb b/spec/unit/converters/boolean/boolean_to_integer_spec.rb
deleted file mode 100644
index d2d9dbc..0000000
--- a/spec/unit/converters/boolean/boolean_to_integer_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::BooleanConverters::BooleanToIntegerConverter, '.call' do
-
- subject(:converter) { described_class.new }
-
- it "converts true to 1 value" do
- expect(converter.call(true)).to eq(1)
- end
-
- it "converts false to 0 value" do
- expect(converter.call(false)).to eq(0)
- end
-
- it "fails to convert in strict mode" do
- expect {
- converter.call('unknown', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-
- it "returns value in non-strict mode" do
- expect(converter.call('unknown', strict: false)).to eq('unknown')
- end
-end
diff --git a/spec/unit/converters/boolean/integer_to_boolean_spec.rb b/spec/unit/converters/boolean/integer_to_boolean_spec.rb
deleted file mode 100644
index ac6cef2..0000000
--- a/spec/unit/converters/boolean/integer_to_boolean_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::BooleanConverters::IntegerToBooleanConverter, '.call' do
-
- subject(:converter) { described_class.new }
-
- it "converts 1 to true value" do
- expect(converter.call(1)).to eq(true)
- end
-
- it "converts 0 to false value" do
- expect(converter.call(0)).to eq(false)
- end
-
- it "fails to convert in strict mode" do
- expect {
- converter.call('1', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-end
diff --git a/spec/unit/converters/boolean/string_to_boolean_spec.rb b/spec/unit/converters/boolean/string_to_boolean_spec.rb
deleted file mode 100644
index af4f46e..0000000
--- a/spec/unit/converters/boolean/string_to_boolean_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::BooleanConverters::StringToBooleanConverter, '.call' do
-
- subject(:converter) { described_class.new(:string, :boolean) }
-
- it "raises error for empty string strict mode" do
- expect {
- converter.call('', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-
- it "fails to convert unkonwn value FOO" do
- expect {
- converter.call('FOO', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-
- it "passes through boolean value" do
- expect(converter.call(true)).to eq(true)
- end
-
- %w[true TRUE t T 1 y Y YES yes on ON].each do |value|
- it "converts '#{value}' to true value" do
- expect(converter.call(value)).to eq(true)
- end
- end
-
- %w[false FALSE f F 0 n N NO No no off OFF].each do |value|
- it "converts '#{value}' to false value" do
- expect(converter.call(value)).to eq(false)
- end
- end
-end
diff --git a/spec/unit/converters/boolean_spec.rb b/spec/unit/converters/boolean_spec.rb
new file mode 100644
index 0000000..df9e791
--- /dev/null
+++ b/spec/unit/converters/boolean_spec.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+RSpec.describe Necromancer::BooleanConverters, "#call" do
+ describe ":string -> :boolean" do
+ subject(:converter) {
+ described_class::StringToBooleanConverter.new(:string, :boolean)
+ }
+
+ it "passes through boolean value" do
+ expect(converter.(true)).to eq(true)
+ end
+
+ %w[true TRUE t T 1 y Y YES yes on ON].each do |value|
+ it "converts '#{value}' to true value" do
+ expect(converter.(value)).to eq(true)
+ end
+ end
+
+ %w[false FALSE f F 0 n N NO No no off OFF].each do |value|
+ it "converts '#{value}' to false value" do
+ expect(converter.(value)).to eq(false)
+ end
+ end
+
+ it "raises error for empty string strict mode" do
+ expect {
+ converter.("", strict: true)
+ }.to raise_error(Necromancer::ConversionTypeError)
+ end
+
+ it "fails to convert unkonwn value FOO" do
+ expect {
+ converter.("FOO", strict: true)
+ }.to raise_error(Necromancer::ConversionTypeError)
+ end
+ end
+
+ describe ":boolean -> :integer" do
+ subject(:converter) {
+ described_class::BooleanToIntegerConverter.new(:boolean, :integer)
+ }
+
+ {
+ true => 1,
+ false => 0,
+ "unknown" => "unknown"
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+
+ it "fails to convert in strict mode" do
+ expect {
+ converter.("unknown", strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'unknown' could not be converted from `boolean` into `integer`"
+ )
+ end
+ end
+
+ describe ":integer -> :boolean" do
+ subject(:converter) { described_class::IntegerToBooleanConverter.new }
+
+ {
+ 1 => true,
+ 0 => false,
+ "unknown" => "unknown"
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+
+ it "fails to convert in strict mode" do
+ expect {
+ converter.("1", strict: true)
+ }.to raise_error(Necromancer::ConversionTypeError)
+ end
+ end
+end
diff --git a/spec/unit/converters/date_time/string_to_date_spec.rb b/spec/unit/converters/date_time/string_to_date_spec.rb
deleted file mode 100644
index 0f68ee7..0000000
--- a/spec/unit/converters/date_time/string_to_date_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::DateTimeConverters::StringToDateConverter, '.call' do
-
- subject(:converter) { described_class.new(:string, :date) }
-
- it "converts '1-1-2015' to date value" do
- expect(converter.call('1-1-2015')).to eq(Date.parse('2015/01/01'))
- end
-
- it "converts '2014/12/07' to date value" do
- expect(converter.call('2014/12/07')).to eq(Date.parse('2014/12/07'))
- end
-
- it "converts '2014-12-07' to date value" do
- expect(converter.call('2014-12-07')).to eq(Date.parse('2014/12/07'))
- end
-
- it "fails to convert in strict mode" do
- expect {
- converter.call('2014 - 12 - 07', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-end
diff --git a/spec/unit/converters/date_time/string_to_datetime_spec.rb b/spec/unit/converters/date_time/string_to_datetime_spec.rb
deleted file mode 100644
index 76258b4..0000000
--- a/spec/unit/converters/date_time/string_to_datetime_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::DateTimeConverters::StringToDateTimeConverter, '.call' do
-
- subject(:converter) { described_class.new(:string, :datetime) }
-
- it "converts '2014/12/07' to date value" do
- expect(converter.call('2014/12/07')).to eq(DateTime.parse('2014/12/07'))
- end
-
- it "converts '2014-12-07' to date value" do
- expect(converter.call('2014-12-07')).to eq(DateTime.parse('2014-12-07'))
- end
-
- it "converts '7th December 2014' to datetime value" do
- expect(converter.call('7th December 2014')).
- to eq(DateTime.parse('2014-12-07'))
- end
-
- it "converts '7th December 2014 17:19:44' to datetime value" do
- expect(converter.call('7th December 2014 17:19:44')).
- to eq(DateTime.parse('2014-12-07 17:19:44'))
- end
-
- it "fails to convert in strict mode" do
- expect {
- converter.call('2014 - 12 - 07', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-end
diff --git a/spec/unit/converters/date_time/string_to_time_spec.rb b/spec/unit/converters/date_time/string_to_time_spec.rb
deleted file mode 100644
index 959f015..0000000
--- a/spec/unit/converters/date_time/string_to_time_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::DateTimeConverters::StringToTimeConverter, '.call' do
-
- subject(:converter) { described_class.new(:string, :time) }
-
- it "converts to time instance" do
- expect(converter.call('01/01/2015')).to be_a(Time)
- end
-
- it "converts '01/01/2015' to time value" do
- expect(converter.call('01/01/2015')).to eq(Time.parse('01/01/2015'))
- end
-
- it "converts '01/01/2015 08:35' to time value" do
- expect(converter.call('01/01/2015 08:35')).to eq(Time.parse('01/01/2015 08:35'))
- end
-
- it "converts '12:35' to time value" do
- expect(converter.call('12:35')).to eq(Time.parse('12:35'))
- end
-
- it "fails to convert in strict mode" do
- expect {
- converter.call('11-13-2015', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-end
diff --git a/spec/unit/converters/date_time_spec.rb b/spec/unit/converters/date_time_spec.rb
new file mode 100644
index 0000000..37bd080
--- /dev/null
+++ b/spec/unit/converters/date_time_spec.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+RSpec.describe Necromancer::DateTimeConverters, "#call" do
+ describe ":string -> :date" do
+ subject(:converter) {
+ described_class::StringToDateConverter.new(:string, :date)
+ }
+
+ {
+ "" => "",
+ "1-1-2015" => Date.parse("2015/01/01"),
+ "2014/12/07" => Date.parse("2014/12/07"),
+ "2014-12-07" => Date.parse("2014/12/07")
+ }.each do |actual, expected|
+ it "converts #{actual.inspect} to range type" do
+ expect(converter.(actual)).to eql(expected)
+ end
+ end
+
+ it "fails to convert in strict mode" do
+ expect {
+ converter.("2014 - 12 - 07", strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'2014 - 12 - 07' could not be converted from `string` into `date`"
+ )
+ end
+ end
+
+ describe ":string -> :datetime" do
+ subject(:converter) {
+ described_class::StringToDateTimeConverter.new(:string, :datetime)
+ }
+
+ {
+ "" => "",
+ "2014/12/07" => DateTime.parse("2014/12/07"),
+ "2014-12-07" => DateTime.parse("2014-12-07"),
+ "7th December 2014" => DateTime.parse("2014-12-07"),
+ "7th December 2014 17:19:44" => DateTime.parse("2014-12-07 17:19:44")
+ }.each do |actual, expected|
+ it "converts #{actual.inspect} to range type" do
+ expect(converter.(actual)).to eql(expected)
+ end
+ end
+
+ it "fails to convert in strict mode" do
+ expect {
+ converter.("2014 - 12 - 07", strict: true)
+ }.to raise_error(Necromancer::ConversionTypeError)
+ end
+ end
+
+ describe ":string -> :time" do
+ subject(:converter) {
+ described_class::StringToTimeConverter.new(:string, :time)
+ }
+
+ {
+ "" => "",
+ "01/01/2015" => Time.parse("01/01/2015"),
+ "01/01/2015 08:35" => Time.parse("01/01/2015 08:35"),
+ "12:35" => Time.parse("12:35")
+ }.each do |actual, expected|
+ it "converts #{actual.inspect} to range type" do
+ expect(converter.(actual)).to eql(expected)
+ end
+ end
+
+ it "fails to convert in strict mode" do
+ expect {
+ converter.("11-13-2015", strict: true)
+ }.to raise_error(Necromancer::ConversionTypeError)
+ end
+ end
+end
diff --git a/spec/unit/converters/hash_spec.rb b/spec/unit/converters/hash_spec.rb
new file mode 100644
index 0000000..8eaf96e
--- /dev/null
+++ b/spec/unit/converters/hash_spec.rb
@@ -0,0 +1,108 @@
+# frozen_string_literal: true
+
+RSpec.describe Necromancer::HashConverters, "#call" do
+ describe ":string -> :hash" do
+ subject(:converter) { described_class::StringToHashConverter.new }
+
+ {
+ "a=1" => { a: "1" },
+ "a=1&b=2" => { a: "1", b: "2" },
+ "a= & b=2" => { a: "", b: "2" },
+ "a=1 & b=2 & a=3" => { a: %w[1 3], b: "2" },
+ "a:1 b:2" => { a: "1", b: "2" },
+ "a:1 b:2 a:3" => { a: %w[1 3], b: "2" }
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+ end
+
+ describe ":string -> :int_hash" do
+ subject(:converter) { described_class::StringToIntegerHashConverter.new }
+
+ {
+ "a=1 & b=2 & a=3" => { a: [1, 3], b: 2 },
+ "a:1 b:2 c:3" => { a: 1, b: 2, c: 3 },
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eq(obj)
+ end
+ end
+
+ it "fails to convert '1.2o' value in strict mode" do
+ expect {
+ converter.("a=1.2o", strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'1.2o' could not be converted from `string` into `integer`"
+ )
+ end
+ end
+
+ describe ":string -> :float_hash" do
+ subject(:converter) { described_class::StringToFloatHashConverter.new }
+
+ {
+ "a=1 & b=2 & a=3" => { a: [1.0, 3.0], b: 2.0 },
+ "a:1 b:2 c:3" => { a: 1.0, b: 2.0, c: 3.0 }
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eql(obj)
+ end
+ end
+
+ it "fails to convert '1.2o' value in strict mode" do
+ expect {
+ converter.("a=1.2o", strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'1.2o' could not be converted from `string` into `float`"
+ )
+ end
+ end
+
+ describe ":string -> :numeric_hash" do
+ subject(:converter) { described_class::StringToNumericHashConverter.new }
+
+ {
+ "a=1 & b=2.0 & a=3.0" => { a: [1, 3.0], b: 2.0 },
+ "a:1 b:2.0 c:3.0" => { a: 1, b: 2.0, c: 3.0 }
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eql(obj)
+ end
+ end
+
+ it "fails to convert '1.2o' value in strict mode" do
+ expect {
+ converter.("a=1.2o", strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'1.2o' could not be converted from `string` into `numeric`"
+ )
+ end
+ end
+
+ describe ":string -> :bool_hash" do
+ subject(:converter) { described_class::StringToBooleanHashConverter.new }
+
+ {
+ "a=t & b=t & a=f" => { a: [true, false], b: true },
+ "a:yes b:no c:t" => { a: true, b: false, c: true }
+ }.each do |input, obj|
+ it "converts #{input.inspect} to #{obj.inspect}" do
+ expect(converter.(input)).to eql(obj)
+ end
+ end
+
+ it "fails to convert '1.2o' value in strict mode" do
+ expect {
+ converter.("a=1.2", strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'1.2' could not be converted from `string` into `boolean`"
+ )
+ end
+ end
+end
diff --git a/spec/unit/converters/numeric/string_to_float_spec.rb b/spec/unit/converters/numeric/string_to_float_spec.rb
deleted file mode 100644
index 5bd4e81..0000000
--- a/spec/unit/converters/numeric/string_to_float_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::NumericConverters::StringToFloatConverter, '.call' do
-
- subject(:converter) { described_class.new(:string, :float) }
-
- it "raises error for empty string in strict mode" do
- expect {
- converter.call('', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-
- {
- '1' => 1.0,
- '+1' => 1.0,
- '-1' => -1.0,
- '1e1' => 10.0,
- '1e-1' => 0.1,
- '-1e1' => -10.0,
- '-1e-1' => -0.1,
- '1.0' => 1.0,
- '1.0e+1' => 10.0,
- '1.0e-1' => 0.1,
- '-1.0e+1' => -10.0,
- '-1.0e-1' => -0.1,
- '.1' => 0.1,
- '.1e+1' => 1.0,
- '.1e-1' => 0.01,
- '-.1e+1' => -1.0,
- '-.1e-1' => -0.01
- }.each do |actual, expected|
- it "converts '#{actual}' to float value" do
- expect(converter.call(actual)).to eql(expected)
- end
- end
-
- it "failse to convert '1.2a' in strict mode" do
- expect {
- converter.call('1.2a', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-
- it "converts '1.2a' in non-strict mode" do
- expect(converter.call('1.2a', strict: false)).to eq(1.2)
- end
-end
diff --git a/spec/unit/converters/numeric/string_to_integer_spec.rb b/spec/unit/converters/numeric/string_to_integer_spec.rb
deleted file mode 100644
index c344d12..0000000
--- a/spec/unit/converters/numeric/string_to_integer_spec.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::NumericConverters::StringToIntegerConverter, '.call' do
-
- subject(:converter) { described_class.new(:string, :integer) }
-
- {
- '1' => 1,
- '+1' => 1,
- '-1' => -1,
- '1e+1' => 1,
- '+1e-1' => 1,
- '-1e1' => -1,
- '-1e-1' => -1,
- '1.0' => 1,
- '1.0e+1' => 1,
- '1.0e-1' => 1,
- '-1.0e+1' => -1,
- '-1.0e-1' => -1,
- '.1' => 0,
- '.1e+1' => 0,
- '.1e-1' => 0,
- '-.1e+1' => 0,
- '-.1e-1' => 0
- }.each do |actual, expected|
- it "converts '#{actual}' to float value" do
- expect(converter.call(actual)).to eql(expected)
- end
- end
-
- it "raises error for empty string in strict mode" do
- expect {
- converter.call('', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-
- it "converts empty string to 0 in non-strict mode" do
- expect(converter.call('', strict: false)).to eq(0)
- end
-
- it "raises error for float in strict mode" do
- expect {
- converter.call('1.2', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-
- it "converts float to integer in non-strict mode" do
- expect(converter.call(1.2)).to eq(1)
- end
-
- it "converts mixed string to integer in non-strict mode" do
- expect(converter.call('1abc')).to eq(1)
- end
-
- it "raises error for mixed string in strict mode" do
- expect {
- converter.call('1abc', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-end
diff --git a/spec/unit/converters/numeric/string_to_numeric_spec.rb b/spec/unit/converters/numeric/string_to_numeric_spec.rb
deleted file mode 100644
index 0eb8511..0000000
--- a/spec/unit/converters/numeric/string_to_numeric_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::NumericConverters::StringToNumericConverter, '.call' do
-
- subject(:converter) { described_class.new(:string, :numeric) }
-
- {
- '1' => 1,
- '+1' => 1,
- '-1' => -1,
- '1e1' => 10.0,
- '1e-1' => 0.1,
- '-1e1' => -10.0,
- '-1e-1' => -0.1,
- '1.0' => 1.0,
- '1.0e+1' => 10.0,
- '1.0e-1' => 0.1,
- '-1.0e+1' => -10.0,
- '-1.0e-1' => -0.1,
- '.1' => 0.1,
- '.1e+1' => 1.0,
- '.1e-1' => 0.01,
- '-.1e+1' => -1.0,
- '-.1e-1' => -0.01
- }.each do |actual, expected|
- it "converts '#{actual}' to '#{expected}'" do
- expect(converter.call(actual)).to eql(expected)
- end
- end
-end
diff --git a/spec/unit/converters/numeric_spec.rb b/spec/unit/converters/numeric_spec.rb
new file mode 100644
index 0000000..a8bfec2
--- /dev/null
+++ b/spec/unit/converters/numeric_spec.rb
@@ -0,0 +1,147 @@
+# frozen_string_literal: true
+
+RSpec.describe Necromancer::NumericConverters, "#call" do
+ describe ":string -> :float" do
+ subject(:converter) {
+ described_class::StringToFloatConverter.new(:string, :float)
+ }
+
+ {
+ "" => 0.0,
+ "1" => 1.0,
+ "+1" => 1.0,
+ "1.2a" => 1.2,
+ "-1" => -1.0,
+ "1e1" => 10.0,
+ "1e-1" => 0.1,
+ "-1e1" => -10.0,
+ "-1e-1" => -0.1,
+ "1.0" => 1.0,
+ "1.0e+1" => 10.0,
+ "1.0e-1" => 0.1,
+ "-1.0e+1" => -10.0,
+ "-1.0e-1" => -0.1,
+ ".1" => 0.1,
+ ".1e+1" => 1.0,
+ ".1e-1" => 0.01,
+ "-.1e+1" => -1.0,
+ "-.1e-1" => -0.01,
+ " 1. 10 " => 1.0,
+ " 1.0" => 1.0,
+ " .1 " => 0.1,
+ " -1.1 " => -1.1,
+ " -1 . 1" => -1.0
+ }.each do |actual, expected|
+ it "converts '#{actual}' to float value" do
+ expect(converter.(actual)).to eql(expected)
+ end
+ end
+
+ it "raises error for empty string in strict mode" do
+ expect {
+ converter.("", strict: true)
+ }.to raise_error(Necromancer::ConversionTypeError)
+ end
+
+ it "fails to convert '1.2a' in strict mode" do
+ expect {
+ converter.("1.2a", strict: true)
+ }.to raise_error(
+ Necromancer::ConversionTypeError,
+ "'1.2a' could not be converted from `string` into `float`"
+ )
+ end
+ end
+
+ describe ":string -> :integer" do
+ subject(:converter) {
+ described_class::StringToIntegerConverter.new(:string, :integer)
+ }
+
+ {
+ "" => 0,
+ "1" => 1,
+ "1ab" => 1,
+ "+1" => 1,
+ "-1" => -1,
+ "1e+1" => 1,
+ "+1e-1" => 1,
+ "-1e1" => -1,
+ "-1e-1" => -1,
+ "1.0" => 1,
+ "1.0e+1" => 1,
+ "1.0e-1" => 1,
+ "-1.0e+1" => -1,
+ "-1.0e-1" => -1,
+ ".1" => 0,
+ ".1e+1" => 0,
+ ".1e-1" => 0,
+ "-.1e+1" => 0,
+ "-.1e-1" => 0,
+ " 1 00" => 1,
+ " 1 " => 1,
+ " -1 " => -1
+ }.each do |actual, expected|
+ it "converts '#{actual}' to float value" do
+ expect(converter.(actual)).to eql(expected)
+ end
+ end
+
+ it "raises error for empty string in strict mode" do
+ expect {
+ converter.("", strict: true)
+ }.to raise_error(Necromancer::ConversionTypeError)
+ end
+
+ it "raises error for float in strict mode" do
+ expect {
+ converter.("1.2", strict: true)
+ }.to raise_error(Necromancer::ConversionTypeError)
+ end
+
+ it "raises error for mixed string in strict mode" do
+ expect {
+ converter.("1abc", strict: true)
+ }.to raise_error(Necromancer::ConversionTypeError)
+ end
+ end
+
+ describe ":string -> :numeric" do
+ subject(:converter) {
+ described_class::StringToNumericConverter.new(:string, :numeric)
+ }
+
+ {
+ "" => 0,
+ "1" => 1,
+ "+1" => 1,
+ "-1" => -1,
+ "1e1" => 10.0,
+ "1e-1" => 0.1,
+ "-1e1" => -10.0,
+ "-1e-1" => -0.1,
+ "1.0" => 1.0,
+ "1.0e+1" => 10.0,
+ "1.0e-1" => 0.1,
+ "-1.0e+1" => -10.0,
+ "-1.0e-1" => -0.1,
+ ".1" => 0.1,
+ ".1e+1" => 1.0,
+ ".1e-1" => 0.01,
+ "-.1e+1" => -1.0,
+ "-.1e-1" => -0.01,
+ " 1 00" => 1,
+ " 1 " => 1,
+ " -1 " => -1,
+ " 1. 10 " => 1.0,
+ " 1.0" => 1.0,
+ " .1 " => 0.1,
+ " -1.1 " => -1.1,
+ " -1 . 1" => -1.0
+ }.each do |actual, expected|
+ it "converts '#{actual}' to '#{expected}'" do
+ expect(converter.(actual)).to eql(expected)
+ end
+ end
+ end
+end
diff --git a/spec/unit/converters/range/string_to_range_spec.rb b/spec/unit/converters/range/string_to_range_spec.rb
deleted file mode 100644
index b3c4f88..0000000
--- a/spec/unit/converters/range/string_to_range_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Necromancer::RangeConverters::StringToRangeConverter, '.call' do
-
- subject(:converter) { described_class.new }
-
- it "raises error for empty string in strict mode" do
- expect {
- converter.call('', strict: true)
- }.to raise_error(Necromancer::ConversionTypeError)
- end
-
- it "returns value in non-strict mode" do
- expect(converter.call('', strict: false)).to eq('')
- end
-
- {
- '1' => 1..1,
- '1..10' => 1..10,
- '1-10' => 1..10,
- '1,10' => 1..10,
- '1...10' => 1...10,
- '-1..10' => -1..10,
- '1..-10' => 1..-10,
- 'a..z' => 'a'..'z',
- 'a-z' => 'a'..'z',
- 'A-Z' => 'A'..'Z'
- }.each do |actual, expected|
- it "converts '#{actual}' to range type" do
- expect(converter.call(actual)).to eql(expected)
- end
- end
-end
diff --git a/spec/unit/converters/range_spec.rb b/spec/unit/converters/range_spec.rb
new file mode 100644
index 0000000..58df860
--- /dev/null
+++ b/spec/unit/converters/range_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+RSpec.describe Necromancer::RangeConverters, "#call" do
+ describe ":string -> :range" do
+ subject(:converter) { described_class::StringToRangeConverter.new }
+
+ {
+ "" => "",
+ "a" => "a",
+ "1" => 1..1,
+ "1.0" => 1.0..1.0,
+ "1..10" => 1..10,
+ "1.0..10.0" => 1.0..10.0,
+ "1-10" => 1..10,
+ "1 , 10" => 1..10,
+ "1...10" => 1...10,
+ "1 . . 10" => 1..10,
+ "-1..10" => -1..10,
+ "1..-10" => 1..-10,
+ "a..z" => "a".."z",
+ "a . . . z" => "a"..."z",
+ "a-z" => "a".."z",
+ "A , Z" => "A".."Z"
+ }.each do |actual, expected|
+ it "converts #{actual.inspect} to range type" do
+ expect(converter.(actual)).to eql(expected)
+ end
+ end
+
+ it "raises error for empty string in strict mode" do
+ expect {
+ converter.("", strict: true)
+ }.to raise_error(Necromancer::ConversionTypeError)
+ end
+ end
+end
diff --git a/spec/unit/inspect_spec.rb b/spec/unit/inspect_spec.rb
index 5659e79..1403435 100644
--- a/spec/unit/inspect_spec.rb
+++ b/spec/unit/inspect_spec.rb
@@ -1,14 +1,20 @@
# frozen_string_literal: true
-RSpec.describe Necromancer, '.inspect' do
+RSpec.describe Necromancer, ".inspect" do
subject(:converter) { described_class.new }
it "inspects converter instance" do
- expect(converter.inspect).to eq("#<Necromancer::Context@#{converter.object_id} @config=#{converter.configuration}>")
+ expect(converter.inspect).to eq(
+ "#<Necromancer::Context@#{converter.object_id} " \
+ "@config=#{converter.configuration}>"
+ )
end
it "inspects conversion target" do
conversion = converter.convert(11)
- expect(conversion.inspect).to eq("#<Necromancer::ConversionTarget@#{conversion.object_id} @object=11, @source=integer>")
+ expect(conversion.inspect).to eq(
+ "#<Necromancer::ConversionTarget@#{conversion.object_id} " \
+ "@object=11, @source=integer>"
+ )
end
end
diff --git a/spec/unit/new_spec.rb b/spec/unit/new_spec.rb
index df7e9c3..83ac31a 100644
--- a/spec/unit/new_spec.rb
+++ b/spec/unit/new_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
-RSpec.describe Necromancer, '#new' do
-
+RSpec.describe Necromancer, "#new" do
subject(:converter) { described_class.new }
it "creates context" do
diff --git a/spec/unit/register_spec.rb b/spec/unit/register_spec.rb
index 002cadd..7995788 100644
--- a/spec/unit/register_spec.rb
+++ b/spec/unit/register_spec.rb
@@ -1,15 +1,17 @@
# frozen_string_literal: true
-RSpec.describe Necromancer, '.register' do
+RSpec.describe Necromancer, ".register" do
it "allows ro register converter" do
converter = described_class.new
- UpcaseConverter = Struct.new(:source, :target) do
- def call(value, **options)
+ stub_const("UpcaseConverter", Struct.new(:source, :target) do
+ def call(value, **_options)
value.to_s.upcase
end
- end
+ end)
+
upcase_converter = UpcaseConverter.new(:string, :upcase)
+
expect(converter.register(upcase_converter)).to eq(true)
- expect(converter.convert('magic').to(:upcase)).to eq('MAGIC')
+ expect(converter.convert("magic").to(:upcase)).to eq("MAGIC")
end
end
diff --git a/tasks/console.rake b/tasks/console.rake
index 7dbb944..79b0079 100644
--- a/tasks/console.rake
+++ b/tasks/console.rake
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-desc 'Load gem inside irb console'
+desc "Load gem inside irb console"
task :console do
- require 'irb'
- require 'irb/completion'
- require_relative '../lib/necromancer'
+ require "irb"
+ require "irb/completion"
+ require_relative "../lib/necromancer"
ARGV.clear
IRB.start
end
-task :c => :console
+task c: :console
diff --git a/tasks/coverage.rake b/tasks/coverage.rake
index e7c9050..247724a 100644
--- a/tasks/coverage.rake
+++ b/tasks/coverage.rake
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-desc 'Measure code coverage'
+desc "Measure code coverage"
task :coverage do
begin
- original, ENV['COVERAGE'] = ENV['COVERAGE'], 'true'
- Rake::Task['spec'].invoke
+ original, ENV["COVERAGE"] = ENV["COVERAGE"], "true"
+ Rake::Task["spec"].invoke
ensure
- ENV['COVERAGE'] = original
+ ENV["COVERAGE"] = original
end
end
diff --git a/tasks/spec.rake b/tasks/spec.rake
index c4373c8..d986d67 100644
--- a/tasks/spec.rake
+++ b/tasks/spec.rake
@@ -1,29 +1,28 @@
# frozen_string_literal: true
begin
- require 'rspec/core/rake_task'
+ require "rspec/core/rake_task"
- desc 'Run all specs'
+ desc "Run all specs"
RSpec::Core::RakeTask.new(:spec) do |task|
- task.pattern = 'spec/{unit,integration}{,/*/**}/*_spec.rb'
+ task.pattern = "spec/{unit,integration}{,/*/**}/*_spec.rb"
end
namespace :spec do
- desc 'Run unit specs'
+ desc "Run unit specs"
RSpec::Core::RakeTask.new(:unit) do |task|
- task.pattern = 'spec/unit{,/*/**}/*_spec.rb'
+ task.pattern = "spec/unit{,/*/**}/*_spec.rb"
end
- desc 'Run integration specs'
+ desc "Run integration specs"
RSpec::Core::RakeTask.new(:integration) do |task|
- task.pattern = 'spec/integration{,/*/**}/*_spec.rb'
+ task.pattern = "spec/integration{,/*/**}/*_spec.rb"
end
end
-
rescue LoadError
%w[spec spec:unit spec:integration].each do |name|
task name do
- $stderr.puts "In order to run #{name}, do `gem install rspec`"
+ warn "In order to run #{name}, do `gem install rspec`"
end
end
end
Debdiff
[The following lists of changes regard files as different if they have different names, permissions or owners.]
Files in second set of .debs but not in first
-rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/configuration.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/context.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/conversion_target.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/conversions.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/converter.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/converters/array.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/converters/boolean.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/converters/date_time.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/converters/hash.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/converters/numeric.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/converters/range.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/null_converter.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.7.0/lib/necromancer/version.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/specifications/necromancer-0.7.0.gemspec
Files in first set of .debs but not in second
-rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer/configuration.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer/context.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer/conversion_target.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer/conversions.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer/converter.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer/converters/array.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer/converters/boolean.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer/converters/date_time.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer/converters/numeric.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer/converters/range.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer/null_converter.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/lib/necromancer/version.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/tasks/console.rake -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/tasks/coverage.rake -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/necromancer-0.5.1/tasks/spec.rake -rw-r--r-- root/root /usr/share/rubygems-integration/all/specifications/necromancer-0.5.1.gemspec
No differences were encountered in the control files