foraneus 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -13
- data/README.md +3 -1
- data/lib/foraneus/converters/boolean.rb +6 -0
- data/lib/foraneus/converters/date.rb +3 -0
- data/lib/foraneus/converters/decimal.rb +4 -32
- data/lib/foraneus/converters/float.rb +37 -13
- data/lib/foraneus/converters/integer.rb +3 -0
- data/lib/foraneus/converters/noop.rb +6 -0
- data/lib/foraneus/converters/string.rb +6 -0
- data/lib/foraneus.rb +7 -3
- data/spec/lib/foraneus/converters/float_converter_spec.rb +0 -16
- data/spec/lib/foraneus_spec.rb +65 -13
- metadata +29 -29
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
Mjc1YzUwODZhMTRiZmFhNTcxZjljYTQ3YzY1Nzk3NDA3Y2YyOTkyZQ==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9cc94a9dc63702c1d2b3c8cbfb61fb4df4c0184c
|
4
|
+
data.tar.gz: a17c6451c968d63a195d242c95633aa9a10430d2
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
MzM1YjJmNzNiNzQ0YWU4MTY4ZDcxNTkzNjMzZTdjMjY5ZTdiNDY4ODJlYjdh
|
11
|
-
YWRhOWZmNTY0NTBmMDhiMTIyNjk4ZTU4M2ZmODI2NjMwM2ZhZDM=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ZmRmZGI3NjFiODYzOGU1NDNjMGUwMTQ1NTkxODUzNGYwZmYzNzQxZWY0ZTY2
|
14
|
-
NjA4NjZmMjQxYTY5ZGJkNzQwOWYyMGYxN2UxNmVhYzgzYzQ5MzI4ZTZlNTA3
|
15
|
-
YTZhNTUyYWUwZjAwODE4YzBiZThkM2M3NWI1NWNkODg4YjAxMzk=
|
6
|
+
metadata.gz: 72d2b1d0693b01fe09d794b3cfc25f3316ff732e2df92fcfe5316645a5f6063c8c1e8fadae7b2827050297295d4c2c82415d16ce60c33b0a7fac56656ae179e8
|
7
|
+
data.tar.gz: 707019d7e8a43204dea773430eada124306bda384fcff69664b393ac4db9372379cfa11fc1cc61874bcc4e0436c1321d2539d29ab445670a0a75b43c594c102b
|
data/README.md
CHANGED
@@ -91,11 +91,13 @@ Converters have two interrelated responsibilities:
|
|
91
91
|
- Parse data, like the string `"3,000"`, into an object, `like 3_000`.
|
92
92
|
- Serialize data, like integer `3_000`, into string `"3,000"`
|
93
93
|
|
94
|
-
A converter is simply an object that responds to `#parse(s)
|
94
|
+
A converter is simply an object that responds to `#parse(s)`, `#raw(v)`, and `#opts` methods.
|
95
95
|
|
96
96
|
When `#parse(s)` raises a StandardError exception, or any of its descendants, the exception is
|
97
97
|
rescued and a Foraneus::Error instance is added to `Foraneus#errors` map.
|
98
98
|
|
99
|
+
`#opts` should return the opts hash used to instantiate the converter.
|
100
|
+
|
99
101
|
Built-in converters:
|
100
102
|
|
101
103
|
- Boolean
|
@@ -8,6 +8,12 @@ class Foraneus
|
|
8
8
|
# When converting to a raw value, a true value => 'true', a false value => 'false'.
|
9
9
|
class Boolean
|
10
10
|
|
11
|
+
attr_reader :opts
|
12
|
+
|
13
|
+
def initialize(opts = {})
|
14
|
+
@opts = opts
|
15
|
+
end
|
16
|
+
|
11
17
|
# @return [Boolean]
|
12
18
|
def parse(s)
|
13
19
|
if s == 'true'
|
@@ -1,34 +1,14 @@
|
|
1
1
|
require 'bigdecimal'
|
2
|
+
require 'foraneus/converters/float'
|
2
3
|
|
3
4
|
class Foraneus
|
4
5
|
module Converters
|
5
6
|
|
6
|
-
class Decimal
|
7
|
-
DEFAULT_SEPARATOR = '.'
|
8
|
-
|
9
|
-
DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
|
10
|
-
|
11
|
-
# @param [Hash] opts
|
12
|
-
# @option opts [String] delimiter Thousands delimiter.
|
13
|
-
# @option opts [String] separator Decimal separator.
|
14
|
-
# @option opts [Integer] precision Minimum precision.
|
15
|
-
def initialize(opts = {})
|
16
|
-
@delimiter = opts[:delimiter]
|
17
|
-
@precision = opts[:precision]
|
18
|
-
@separator = opts[:separator] || DEFAULT_SEPARATOR
|
19
|
-
end
|
7
|
+
class Decimal < Foraneus::Converters::Float
|
20
8
|
|
21
9
|
# @return [BigDecimal]
|
22
10
|
def parse(s)
|
23
|
-
|
24
|
-
|
25
|
-
integer_part = (parts[0] || '0')
|
26
|
-
|
27
|
-
if @delimiter
|
28
|
-
integer_part.gsub!(@delimiter, '')
|
29
|
-
end
|
30
|
-
|
31
|
-
fractional_part = parts[1] || '0'
|
11
|
+
integer_part, fractional_part = split(s)
|
32
12
|
|
33
13
|
BigDecimal.new("#{integer_part}.#{fractional_part}")
|
34
14
|
end
|
@@ -36,15 +16,7 @@ class Foraneus
|
|
36
16
|
def raw(v)
|
37
17
|
left, right = v.to_s('F').split('.')
|
38
18
|
|
39
|
-
|
40
|
-
right = add_trailing_zeros(right, @precision - right.length)
|
41
|
-
end
|
42
|
-
|
43
|
-
if @delimiter
|
44
|
-
left.gsub!(DELIMITED_REGEX) { "#{$1}#{@delimiter}" }
|
45
|
-
end
|
46
|
-
|
47
|
-
"#{left}#{@separator}#{right}"
|
19
|
+
join(left, right)
|
48
20
|
end
|
49
21
|
|
50
22
|
private
|
@@ -7,11 +7,15 @@ class Foraneus
|
|
7
7
|
|
8
8
|
DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
|
9
9
|
|
10
|
+
attr_reader :opts
|
11
|
+
|
10
12
|
# @param [Hash] opts
|
11
13
|
# @option opts [String] delimiter Thousands delimiter.
|
12
14
|
# @option opts [String] separator Decimal separator.
|
13
15
|
# @option opts [Integer] precision Minimum precision.
|
14
16
|
def initialize(opts = {})
|
17
|
+
@opts = opts
|
18
|
+
|
15
19
|
@delimiter = opts[:delimiter]
|
16
20
|
@precision = opts[:precision]
|
17
21
|
@separator = opts[:separator] || DEFAULT_SEPARATOR
|
@@ -19,19 +23,7 @@ class Foraneus
|
|
19
23
|
|
20
24
|
# @return [Float]
|
21
25
|
def parse(s)
|
22
|
-
|
23
|
-
raise ArgumentError, 'invalid value for Float(): ""'
|
24
|
-
end
|
25
|
-
|
26
|
-
parts = s.split(@separator)
|
27
|
-
|
28
|
-
integer_part = parts[0] || '0'
|
29
|
-
|
30
|
-
if @delimiter
|
31
|
-
integer_part.gsub!(@delimiter, '')
|
32
|
-
end
|
33
|
-
|
34
|
-
fractional_part = parts[1] || '0'
|
26
|
+
integer_part, fractional_part = split(s)
|
35
27
|
|
36
28
|
Kernel.Float("#{integer_part}.#{fractional_part}")
|
37
29
|
end
|
@@ -39,6 +31,19 @@ class Foraneus
|
|
39
31
|
def raw(v)
|
40
32
|
left, right = v.to_s.split('.')
|
41
33
|
|
34
|
+
join(left, right)
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
# Joins both integer and fractional parts.
|
39
|
+
#
|
40
|
+
# It adds trailing zeros according to the current precision.
|
41
|
+
#
|
42
|
+
# @param [Integer] left Integer part
|
43
|
+
# @param [Integer] right Fractional part
|
44
|
+
#
|
45
|
+
# @return [String]
|
46
|
+
def join(left, right)
|
42
47
|
if @precision && right.length < @precision
|
43
48
|
right = add_trailing_zeros(right, @precision - right.length)
|
44
49
|
end
|
@@ -50,6 +55,25 @@ class Foraneus
|
|
50
55
|
"#{left}#{@separator}#{right}"
|
51
56
|
end
|
52
57
|
|
58
|
+
# Splits a float representation into its integer and fractional parts.
|
59
|
+
#
|
60
|
+
# @param [String] s
|
61
|
+
#
|
62
|
+
# @return [Array [integer_part, fractional_part] ]
|
63
|
+
def split(s)
|
64
|
+
parts = s.split(@separator)
|
65
|
+
|
66
|
+
integer_part = parts[0] || '0'
|
67
|
+
|
68
|
+
if @delimiter
|
69
|
+
integer_part.gsub!(@delimiter, '')
|
70
|
+
end
|
71
|
+
|
72
|
+
fractional_part = parts[1] || '0'
|
73
|
+
|
74
|
+
[integer_part, fractional_part]
|
75
|
+
end
|
76
|
+
|
53
77
|
private
|
54
78
|
def add_trailing_zeros(s, n)
|
55
79
|
zeros = '0' * n
|
@@ -4,9 +4,12 @@ class Foraneus
|
|
4
4
|
class Integer
|
5
5
|
DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
|
6
6
|
|
7
|
+
attr_reader :opts
|
8
|
+
|
7
9
|
# @param [Hash] opts
|
8
10
|
# @option opts [String] delimiter Thousands delimiter.
|
9
11
|
def initialize(opts = {})
|
12
|
+
@opts = opts
|
10
13
|
@delimiter = opts[:delimiter]
|
11
14
|
end
|
12
15
|
|
@@ -6,6 +6,12 @@ class Foraneus
|
|
6
6
|
# It does not perform any conversion at all. Useful when its needed to have a field but
|
7
7
|
# conversion is handled at another level.
|
8
8
|
class Noop
|
9
|
+
attr_reader :opts
|
10
|
+
|
11
|
+
def initialize(opts = {})
|
12
|
+
@opts = opts
|
13
|
+
end
|
14
|
+
|
9
15
|
# @return [Object]
|
10
16
|
def parse(o)
|
11
17
|
o
|
data/lib/foraneus.rb
CHANGED
@@ -186,11 +186,15 @@ class Foraneus
|
|
186
186
|
field = k.to_s
|
187
187
|
converter = fields[field]
|
188
188
|
|
189
|
-
return unless converter
|
190
|
-
|
191
189
|
foraneus[k] = v
|
192
190
|
|
193
|
-
unless
|
191
|
+
return unless converter
|
192
|
+
|
193
|
+
if (v.nil? || v == '') && converter.opts[:required]
|
194
|
+
raise KeyError, "required parameter not found: #{field.inspect}"
|
195
|
+
elsif v.nil? || v == ''
|
196
|
+
v = nil
|
197
|
+
else
|
194
198
|
v = converter.parse(v)
|
195
199
|
end
|
196
200
|
|
@@ -66,22 +66,6 @@ describe Foraneus::Converters::Float do
|
|
66
66
|
}.to raise_error
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
70
|
-
context 'with empty values' do
|
71
|
-
it 'raises an error' do
|
72
|
-
expect {
|
73
|
-
subject.parse('')
|
74
|
-
}.to raise_error
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
context 'with nil values' do
|
79
|
-
it 'raises an error' do
|
80
|
-
expect {
|
81
|
-
subject.parse(nil)
|
82
|
-
}.to raise_error
|
83
|
-
end
|
84
|
-
end
|
85
69
|
end
|
86
70
|
|
87
71
|
describe '#raw' do
|
data/spec/lib/foraneus_spec.rb
CHANGED
@@ -16,9 +16,11 @@ describe Foraneus do
|
|
16
16
|
|
17
17
|
its(:delay) { should eq(5) }
|
18
18
|
|
19
|
+
its(:data) { should include(:delay => 5) }
|
20
|
+
|
19
21
|
its([:delay]) { should eq('5') }
|
20
22
|
|
21
|
-
its(
|
23
|
+
its(['delay']) { should be_nil }
|
22
24
|
|
23
25
|
its([]) { should include(:delay => '5') }
|
24
26
|
|
@@ -37,18 +39,6 @@ describe Foraneus do
|
|
37
39
|
|
38
40
|
its([]) { should include('delay' => '5') }
|
39
41
|
end
|
40
|
-
|
41
|
-
context 'with nil values' do
|
42
|
-
subject(:form) { form_spec.parse('delay' => nil) }
|
43
|
-
|
44
|
-
its(['delay']) { should eq(nil) }
|
45
|
-
|
46
|
-
its([:delay]) { should eq(nil) }
|
47
|
-
|
48
|
-
its(:data) { should include('delay' => nil) }
|
49
|
-
|
50
|
-
its([]) { should include('delay' => nil) }
|
51
|
-
end
|
52
42
|
end
|
53
43
|
|
54
44
|
context 'with non parseable data' do
|
@@ -80,6 +70,68 @@ describe Foraneus do
|
|
80
70
|
its(:message) { should eq(converter_exception.message) }
|
81
71
|
end
|
82
72
|
end
|
73
|
+
|
74
|
+
context 'with unexpected data' do
|
75
|
+
subject(:form) { form_spec.parse(:position => 'north') }
|
76
|
+
|
77
|
+
it 'does not have a getter for the received param' do
|
78
|
+
expect {
|
79
|
+
form.position
|
80
|
+
}.to raise_error(NoMethodError)
|
81
|
+
end
|
82
|
+
|
83
|
+
its(:data) { should_not include(:position) }
|
84
|
+
|
85
|
+
its([:position]) { should eq('north') }
|
86
|
+
|
87
|
+
its([]) { should include(:position => 'north') }
|
88
|
+
|
89
|
+
it { should be_valid }
|
90
|
+
end
|
91
|
+
|
92
|
+
shared_examples 'an absent parameters handler' do |missing_value|
|
93
|
+
subject(:form) { form_spec.parse(:delay => missing_value) }
|
94
|
+
|
95
|
+
it { should be_valid }
|
96
|
+
|
97
|
+
its(:delay) { should be_nil }
|
98
|
+
|
99
|
+
its(:data) { should include(:delay => nil) }
|
100
|
+
|
101
|
+
its([:delay]) { should eq(missing_value) }
|
102
|
+
|
103
|
+
its([]) { should include(:delay => missing_value) }
|
104
|
+
|
105
|
+
context 'when required field' do
|
106
|
+
let(:converter) { Foraneus::Converters::Integer.new(:required => true) }
|
107
|
+
|
108
|
+
it { should_not be_valid }
|
109
|
+
|
110
|
+
its(:delay) { should be_nil }
|
111
|
+
|
112
|
+
its(:data) { should_not include(:delay) }
|
113
|
+
|
114
|
+
its([:delay]) { should eq(missing_value) }
|
115
|
+
|
116
|
+
its([]) { should include(:delay => missing_value) }
|
117
|
+
|
118
|
+
its([:errors]) { should include(:delay) }
|
119
|
+
|
120
|
+
describe 'an error' do
|
121
|
+
subject(:error) { form[:errors].values.first }
|
122
|
+
|
123
|
+
its(:key) { should eq('KeyError') }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'with nil values' do
|
129
|
+
it_behaves_like 'an absent parameters handler', nil
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'with empty values' do
|
133
|
+
it_behaves_like 'an absent parameters handler', ''
|
134
|
+
end
|
83
135
|
end
|
84
136
|
|
85
137
|
describe '.raw' do
|
metadata
CHANGED
@@ -1,57 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foraneus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gianfranco Zas
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
15
|
-
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 2.14.0
|
20
|
-
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirement: !ruby/object:Gem::Requirement
|
23
21
|
requirements:
|
24
22
|
- - ~>
|
25
23
|
- !ruby/object:Gem::Version
|
26
24
|
version: 2.14.0
|
25
|
+
prerelease: false
|
26
|
+
type: :development
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
29
|
-
|
28
|
+
name: yard-kramdown
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
|
-
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
37
35
|
requirements:
|
38
|
-
- -
|
36
|
+
- - '>='
|
39
37
|
- !ruby/object:Gem::Version
|
40
38
|
version: '0'
|
39
|
+
prerelease: false
|
40
|
+
type: :development
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: yard
|
43
|
-
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
|
-
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
51
49
|
requirements:
|
52
|
-
- -
|
50
|
+
- - '>='
|
53
51
|
- !ruby/object:Gem::Version
|
54
52
|
version: '0'
|
53
|
+
prerelease: false
|
54
|
+
type: :development
|
55
55
|
description: Provides two way transformation mechanisms to external data.
|
56
56
|
email: snmgian@gmail.com
|
57
57
|
executables: []
|
@@ -70,6 +70,7 @@ files:
|
|
70
70
|
- COPYING
|
71
71
|
- COPYING.LESSER
|
72
72
|
- README.md
|
73
|
+
- spec/spec_helper.rb
|
73
74
|
- spec/lib/foraneus_spec.rb
|
74
75
|
- spec/lib/foraneus/converters/noop_converter_spec.rb
|
75
76
|
- spec/lib/foraneus/converters/decimal_converter_spec.rb
|
@@ -78,32 +79,32 @@ files:
|
|
78
79
|
- spec/lib/foraneus/converters/string_converter_spec.rb
|
79
80
|
- spec/lib/foraneus/converters/float_converter_spec.rb
|
80
81
|
- spec/lib/foraneus/converters/boolean_converter_spec.rb
|
81
|
-
- spec/spec_helper.rb
|
82
82
|
homepage: https://github.com/snmgian/foraneus
|
83
83
|
licenses:
|
84
84
|
- LGPL
|
85
85
|
metadata: {}
|
86
|
-
post_install_message:
|
86
|
+
post_install_message:
|
87
87
|
rdoc_options: []
|
88
88
|
require_paths:
|
89
89
|
- lib
|
90
90
|
required_ruby_version: !ruby/object:Gem::Requirement
|
91
91
|
requirements:
|
92
|
-
- -
|
92
|
+
- - '>='
|
93
93
|
- !ruby/object:Gem::Version
|
94
94
|
version: '0'
|
95
95
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
96
|
requirements:
|
97
|
-
- -
|
97
|
+
- - '>='
|
98
98
|
- !ruby/object:Gem::Version
|
99
99
|
version: '0'
|
100
100
|
requirements: []
|
101
|
-
rubyforge_project:
|
102
|
-
rubygems_version: 2.1.
|
103
|
-
signing_key:
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 2.1.9
|
103
|
+
signing_key:
|
104
104
|
specification_version: 4
|
105
105
|
summary: Transforms external data.
|
106
106
|
test_files:
|
107
|
+
- spec/spec_helper.rb
|
107
108
|
- spec/lib/foraneus_spec.rb
|
108
109
|
- spec/lib/foraneus/converters/noop_converter_spec.rb
|
109
110
|
- spec/lib/foraneus/converters/decimal_converter_spec.rb
|
@@ -112,5 +113,4 @@ test_files:
|
|
112
113
|
- spec/lib/foraneus/converters/string_converter_spec.rb
|
113
114
|
- spec/lib/foraneus/converters/float_converter_spec.rb
|
114
115
|
- spec/lib/foraneus/converters/boolean_converter_spec.rb
|
115
|
-
|
116
|
-
has_rdoc:
|
116
|
+
has_rdoc:
|