foraneus 0.0.1 → 0.0.2
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 +15 -0
- data/README.md +64 -4
- data/lib/foraneus/converters/boolean.rb +23 -0
- data/lib/foraneus/converters/date.rb +24 -0
- data/lib/foraneus/converters/decimal.rb +49 -0
- data/lib/foraneus/converters/float.rb +15 -0
- data/lib/foraneus/converters/integer.rb +15 -0
- data/lib/foraneus/converters/string.rb +15 -0
- data/lib/foraneus/errors.rb +4 -55
- data/lib/foraneus.rb +117 -42
- data/spec/lib/foraneus/converters/boolean_converter_spec.rb +36 -0
- data/spec/lib/foraneus/converters/date_converter_spec.rb +59 -0
- data/spec/lib/foraneus/converters/decimal_converter_spec.rb +81 -0
- data/spec/lib/foraneus/converters/float_converter_spec.rb +72 -0
- data/spec/lib/foraneus/converters/integer_converter_spec.rb +73 -0
- data/spec/lib/foraneus/converters/string_converter_spec.rb +18 -0
- data/spec/lib/foraneus_spec.rb +136 -0
- data/spec/spec_helper.rb +2 -0
- metadata +35 -71
- data/lib/foraneus/converters.rb +0 -50
- data/lib/foraneus/hashlike.rb +0 -36
- data/lib/foraneus/markers.rb +0 -9
- data/lib/foraneus/raw_value_set_builder.rb +0 -43
- data/lib/foraneus/simple_converters.rb +0 -79
- data/lib/foraneus/value_set.rb +0 -46
- data/lib/foraneus/value_set_builder.rb +0 -132
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YjUyZWQ0OTM3OTA4MWE0MzBlNmEyZmUzYWI5ZGM2ZTdlYzBiMTJhOQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NTcyZjkzYjM3NWE3N2QzYjQ3MzYyNjMyOGQ3ZTBiZjE1Mjc5Y2VmOQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZTMzMzNhYjg4MmJkYTZkODhmZTllYTgwN2ZhZDQ0NjA5OTM1NWUxNDU5YjA5
|
10
|
+
ZjQ5YzY1NjZhMDc4OThlNmJkN2YxNWE4MDQ0MzQ5YjBjMjMwODQ1MTczZTJl
|
11
|
+
NjExNmI0OWQyMWNlOTNmYjA5NzE0YzUwOWViYjQwZWY2NGU4Mzk=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZjllNzU3NzQxNWUzZGEzOTk2OWMwNWUwZTY1OGQ4NTkxYWNiZWI1Mjg1N2Jh
|
14
|
+
YzMxZjc3YTI1OGM1MWViNzI4ZDg2ZTdjYzYxOWE0YTM1Yzc0ODMxNDI2MDJh
|
15
|
+
MzcxMzVlYWE0ZTM0OThiYmI1NGY1YmUxZmJlOTc1OTI1MmVkZDM=
|
data/README.md
CHANGED
@@ -1,5 +1,65 @@
|
|
1
|
-
|
2
|
-
Copyright (c) 2012 "snmgian", released under LGPL v3 license.
|
1
|
+
# Foraneus
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
## Usage
|
4
|
+
|
5
|
+
``` ruby
|
6
|
+
class MyForm < Foraneus
|
7
|
+
integer :delay
|
8
|
+
float :duration
|
9
|
+
end
|
10
|
+
```
|
11
|
+
|
12
|
+
- From the outside:
|
13
|
+
|
14
|
+
``` ruby
|
15
|
+
form = MyForm.parse(:delay => '5', :duration => '2.14')
|
16
|
+
```
|
17
|
+
|
18
|
+
``` ruby
|
19
|
+
form.delay # => 5
|
20
|
+
form[:delay] # => '5'
|
21
|
+
```
|
22
|
+
|
23
|
+
``` ruby
|
24
|
+
form.data # => { :delay => 5, :duration => 2.14 }
|
25
|
+
form[] # => { :delay => '5', :duration => '2.14' }
|
26
|
+
```
|
27
|
+
|
28
|
+
``` ruby
|
29
|
+
form.valid? # => true
|
30
|
+
form.errors # => {}
|
31
|
+
```
|
32
|
+
|
33
|
+
- From the inside
|
34
|
+
|
35
|
+
``` ruby
|
36
|
+
form = MyForm.new
|
37
|
+
```
|
38
|
+
|
39
|
+
``` ruby
|
40
|
+
form.delay # => nil
|
41
|
+
form[:delay] # => nil
|
42
|
+
```
|
43
|
+
|
44
|
+
- From the inside
|
45
|
+
|
46
|
+
``` ruby
|
47
|
+
form = MyForm.raw(:delay => 5, :duration => 2.14)
|
48
|
+
``` ruby
|
49
|
+
|
50
|
+
``` ruby
|
51
|
+
form.delay # => 5
|
52
|
+
form[:delay] # => '5'
|
53
|
+
```
|
54
|
+
|
55
|
+
``` ruby
|
56
|
+
form.data # => { :delay => 5, :duration => 2.14 }
|
57
|
+
form[] # => { :delay => '5', :duration => '2.14' }
|
58
|
+
```
|
59
|
+
|
60
|
+
|
61
|
+
## License
|
62
|
+
|
63
|
+
This software is licensed under the [LGPL][lgpl] license.
|
64
|
+
|
65
|
+
[lgpl]: https://www.gnu.org/licenses/lgpl.html
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
class Foraneus
|
4
|
+
module Converters
|
5
|
+
|
6
|
+
class Date
|
7
|
+
|
8
|
+
DEFAULT_FORMAT = '%Y-%m-%d'
|
9
|
+
|
10
|
+
def initialize(opts = {})
|
11
|
+
@format = opts[:format] || DEFAULT_FORMAT
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse(s)
|
15
|
+
::Date.strptime(s, @format)
|
16
|
+
end
|
17
|
+
|
18
|
+
def raw(v)
|
19
|
+
v.strftime(@format)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
|
3
|
+
class Foraneus
|
4
|
+
module Converters
|
5
|
+
|
6
|
+
class Decimal
|
7
|
+
DEFAULT_DELIMITER = ','
|
8
|
+
DEFAULT_SEPARATOR = '.'
|
9
|
+
|
10
|
+
DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
|
11
|
+
|
12
|
+
def initialize(opts = {})
|
13
|
+
@delimiter = opts[:delimiter] || DEFAULT_DELIMITER
|
14
|
+
@separator = opts[:separator] || DEFAULT_SEPARATOR
|
15
|
+
@precision = opts[:precision]
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse(s)
|
19
|
+
parts = s.split(@separator)
|
20
|
+
|
21
|
+
integer_part = (parts[0] || '0').gsub(@delimiter, '')
|
22
|
+
fractional_part = parts[1] || '0'
|
23
|
+
|
24
|
+
BigDecimal.new("#{integer_part}.#{fractional_part}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def raw(v)
|
28
|
+
left, right = v.to_s('F').split('.')
|
29
|
+
|
30
|
+
if @precision && right.length < @precision
|
31
|
+
right = add_trailing_zeros(right, @precision - right.length)
|
32
|
+
end
|
33
|
+
|
34
|
+
left.gsub!(DELIMITED_REGEX) { "#{$1}#{@delimiter}" }
|
35
|
+
|
36
|
+
"#{left}#{@separator}#{right}"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def add_trailing_zeros(s, n)
|
41
|
+
zeros = '0' * n
|
42
|
+
|
43
|
+
"#{s}#{zeros}"
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
data/lib/foraneus/errors.rb
CHANGED
@@ -1,59 +1,8 @@
|
|
1
|
-
|
1
|
+
class Foraneus
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
# @!attribute name
|
7
|
-
# @return [String] Name of the field value
|
8
|
-
attr_accessor :name
|
9
|
-
|
10
|
-
# @!attribute value
|
11
|
-
# @return [String] Value attempted to be parsed
|
12
|
-
attr_accessor :value
|
13
|
-
|
14
|
-
# @!attribute expected_type
|
15
|
-
# @return [String] The expected type to be parsed
|
16
|
-
attr_accessor :expected_type
|
17
|
-
|
18
|
-
# @param [String] name The name of the field in the value_set
|
19
|
-
# @param [String] value The value attempted to be parsed
|
20
|
-
# @param [Symbol] expected_type The expected type to be parsed
|
21
|
-
def initialize(name, value, expected_type)
|
22
|
-
@name = name
|
23
|
-
@value = value
|
24
|
-
@expected_type = expected_type
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# Raised on an attempt to create a value_set from invalid value
|
29
|
-
class ValueSetError < StandardError
|
30
|
-
|
31
|
-
# @!attribute value_set
|
32
|
-
# @return [ValueSet] ValueSet with errors
|
33
|
-
attr_accessor :value_set
|
34
|
-
|
35
|
-
# @param [Foraneus::ValueSet] value_set ValueSet with errors
|
36
|
-
def initialize(value_set)
|
37
|
-
@value_set = value_set
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Raised on an attempt to parse an invalid value
|
42
|
-
class ConverterError < StandardError
|
43
|
-
|
44
|
-
# @!attribute value
|
45
|
-
# @return [String] Value attempted to be parsed
|
46
|
-
attr_accessor :value
|
47
|
-
|
48
|
-
# @!attribute value
|
49
|
-
# @return [String] Name of the converter that raised the error
|
50
|
-
attr_accessor :converter_name
|
51
|
-
|
52
|
-
# @param [String] value The value attempted to be parsed
|
53
|
-
# @param [Symbol] converter_name Name of the converter
|
54
|
-
def initialize(value, converter_name)
|
55
|
-
@value = value
|
56
|
-
@converter_name = converter_name
|
3
|
+
Error = Struct.new(:key, :message) do
|
4
|
+
def to_s
|
5
|
+
"#{key} - #{message}"
|
57
6
|
end
|
58
7
|
end
|
59
8
|
|
data/lib/foraneus.rb
CHANGED
@@ -1,57 +1,132 @@
|
|
1
|
+
require_relative 'foraneus/converters/boolean'
|
2
|
+
require_relative 'foraneus/converters/date'
|
3
|
+
require_relative 'foraneus/converters/decimal'
|
4
|
+
require_relative 'foraneus/converters/float'
|
5
|
+
require_relative 'foraneus/converters/integer'
|
6
|
+
require_relative 'foraneus/converters/string'
|
7
|
+
require_relative 'foraneus/errors'
|
8
|
+
|
1
9
|
# Foraneus is library for parsing external data.
|
2
10
|
#
|
3
|
-
# It allows to define value_sets that specify how the external data is structured
|
4
|
-
|
11
|
+
# It allows to define value_sets that specify how the external data is structured
|
12
|
+
# and how it should be parsed.
|
13
|
+
class Foraneus
|
14
|
+
|
15
|
+
attr_accessor :data
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@data = {}
|
19
|
+
@raw_data = {}
|
20
|
+
|
21
|
+
@errors = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.boolean(name)
|
25
|
+
converter = Foraneus::Converters::Boolean.new
|
26
|
+
field(name, converter)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.date(name, *args)
|
30
|
+
converter = Foraneus::Converters::Date.new(*args)
|
31
|
+
field(name, converter)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.decimal(name, *args)
|
35
|
+
converter = Foraneus::Converters::Decimal.new(*args)
|
36
|
+
field(name, converter)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.float(name)
|
40
|
+
converter = Foraneus::Converters::Float.new
|
41
|
+
field(name, converter)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.integer(name)
|
45
|
+
converter = Foraneus::Converters::Integer.new
|
46
|
+
field(name, converter)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.string(name)
|
50
|
+
converter = Foraneus::Converters::String.new
|
51
|
+
field(name, converter)
|
52
|
+
end
|
5
53
|
|
6
|
-
|
54
|
+
def self.field(name, converter)
|
55
|
+
fields[name.to_s] = converter
|
56
|
+
self.send(:attr_accessor, name)
|
57
|
+
end
|
7
58
|
|
8
|
-
|
9
|
-
|
10
|
-
def self.registry
|
11
|
-
@registry
|
59
|
+
def self.fields
|
60
|
+
@fields ||= {}
|
12
61
|
end
|
13
62
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
63
|
+
def self.parse(raw_data)
|
64
|
+
instance = self.new
|
65
|
+
|
66
|
+
parsed_data = {}
|
67
|
+
|
68
|
+
raw_data.each do |k, v|
|
69
|
+
field = k.to_s
|
70
|
+
converter = fields[field]
|
71
|
+
next unless converter
|
18
72
|
|
19
|
-
|
20
|
-
|
73
|
+
instance[k] = v
|
74
|
+
begin
|
75
|
+
v = if v.nil?
|
76
|
+
nil
|
77
|
+
else
|
78
|
+
converter.parse(v)
|
79
|
+
end
|
21
80
|
|
22
|
-
|
81
|
+
instance.send("#{field}=", v)
|
82
|
+
instance.data[k] = v
|
83
|
+
rescue
|
84
|
+
error = Foraneus::Error.new($!.class.name, $!.message)
|
85
|
+
instance.instance_variable_get(:@errors)[k] = error
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
instance
|
23
90
|
end
|
24
91
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
92
|
+
def self.raw(data)
|
93
|
+
instance = self.new
|
94
|
+
|
95
|
+
data.each do |k, v|
|
96
|
+
next unless fields.has_key?(k.to_s)
|
97
|
+
instance.send("#{k}=", v)
|
98
|
+
converter = fields[k.to_s]
|
99
|
+
|
100
|
+
s = if v.nil?
|
101
|
+
nil
|
102
|
+
else
|
103
|
+
converter.raw(v)
|
104
|
+
end
|
35
105
|
|
36
|
-
|
37
|
-
|
106
|
+
instance[k] = s
|
107
|
+
instance.data[k] = v
|
38
108
|
end
|
109
|
+
|
110
|
+
instance
|
39
111
|
end
|
40
112
|
|
41
|
-
|
113
|
+
def [](m = nil)
|
114
|
+
if m == :errors
|
115
|
+
@errors
|
116
|
+
elsif m.nil?
|
117
|
+
@raw_data
|
118
|
+
else
|
119
|
+
@raw_data.fetch(m) do
|
120
|
+
@raw_data[m.to_s]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
42
124
|
|
43
|
-
[
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
:value_set_builder,
|
52
|
-
].each { |f| require_relative "foraneus/#{f}" }
|
53
|
-
|
54
|
-
Foraneus.register(Foraneus::Converters::Boolean)
|
55
|
-
Foraneus.register(Foraneus::Converters::Float)
|
56
|
-
Foraneus.register(Foraneus::Converters::Integer)
|
57
|
-
Foraneus.register(Foraneus::Converters::String)
|
125
|
+
def []=(k, v)
|
126
|
+
@raw_data[k] = v
|
127
|
+
end
|
128
|
+
|
129
|
+
def valid?
|
130
|
+
@errors.empty?
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Foraneus::Converters::Boolean do
|
4
|
+
|
5
|
+
describe '#parse' do
|
6
|
+
it 'returns true with true' do
|
7
|
+
parsed = subject.parse('true')
|
8
|
+
|
9
|
+
parsed.should be_true
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'returns false with sth else' do
|
13
|
+
parsed = subject.parse('false')
|
14
|
+
|
15
|
+
parsed.should be_false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#raw' do
|
20
|
+
it 'returns "true" with true' do
|
21
|
+
subject.raw(true).should eq('true')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'returns "false" with false' do
|
25
|
+
subject.raw(false).should eq('false')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns "false" with nil' do
|
29
|
+
subject.raw(nil).should eq('false')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'returns "true" with everything else' do
|
33
|
+
subject.raw(:default).should eq('true')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Foraneus::Converters::Date do
|
4
|
+
|
5
|
+
subject(:converter) { Foraneus::Converters::Date.new }
|
6
|
+
|
7
|
+
describe '#parse' do
|
8
|
+
|
9
|
+
it 'parses a date representation' do
|
10
|
+
s = '2012-04-13'
|
11
|
+
|
12
|
+
result = converter.parse(s)
|
13
|
+
|
14
|
+
result.year.should eq(2012)
|
15
|
+
result.month.should eq(04)
|
16
|
+
result.day.should eq(13)
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when format is given' do
|
20
|
+
subject(:converter) {
|
21
|
+
Foraneus::Converters::Date.new(:format => '%d/%m/%Y')
|
22
|
+
}
|
23
|
+
|
24
|
+
it 'parses a date representation' do
|
25
|
+
s = '13/04/2012'
|
26
|
+
|
27
|
+
result = converter.parse(s)
|
28
|
+
|
29
|
+
result.year.should eq(2012)
|
30
|
+
result.month.should eq(04)
|
31
|
+
result.day.should eq(13)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#raw' do
|
37
|
+
let(:d) { Date.today }
|
38
|
+
|
39
|
+
it 'returns a date representation' do
|
40
|
+
s = d.strftime('%Y-%m-%d')
|
41
|
+
|
42
|
+
converter.raw(d).should eq(s)
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when format is given' do
|
46
|
+
let(:format) { '%m/%d/%Y' }
|
47
|
+
subject(:converter) {
|
48
|
+
Foraneus::Converters::Date.new(:format => format)
|
49
|
+
}
|
50
|
+
|
51
|
+
it 'returns a date representation' do
|
52
|
+
s = d.strftime(format)
|
53
|
+
|
54
|
+
converter.raw(d).should eq(s)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Foraneus::Converters::Decimal do
|
4
|
+
|
5
|
+
subject(:converter) { Foraneus::Converters::Decimal.new }
|
6
|
+
|
7
|
+
describe '#parse' do
|
8
|
+
it 'parses a decimal representation' do
|
9
|
+
s = '1,234.56'
|
10
|
+
n = BigDecimal.new('1234.56')
|
11
|
+
|
12
|
+
converter.parse(s).should eq(n)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'parses a decimal representation when no integer part' do
|
16
|
+
s = '.56'
|
17
|
+
n = BigDecimal.new('0.56')
|
18
|
+
|
19
|
+
converter.parse(s).should eq(n)
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when separator and delimiter are given' do
|
23
|
+
subject(:converter) {
|
24
|
+
Foraneus::Converters::Decimal.new(:delimiter => '.', :separator => ',')
|
25
|
+
}
|
26
|
+
|
27
|
+
it 'parses a decimal representation' do
|
28
|
+
s = '1.234.567,89'
|
29
|
+
n = BigDecimal.new('1234567.89')
|
30
|
+
|
31
|
+
converter.parse(s).should eq(n)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'parses a decimal representation when no integer part' do
|
35
|
+
s = ',56'
|
36
|
+
n = BigDecimal.new('0.56')
|
37
|
+
|
38
|
+
converter.parse(s).should eq(n)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#raw' do
|
44
|
+
let(:n) { BigDecimal.new('1234567.89') }
|
45
|
+
|
46
|
+
it 'returns a decimal representation' do
|
47
|
+
s = '1,234,567.89'
|
48
|
+
|
49
|
+
converter.raw(n).should eq(s)
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when separator and delimiter are given' do
|
53
|
+
subject(:converter) {
|
54
|
+
Foraneus::Converters::Decimal.new(:delimiter => '.', :separator => ',')
|
55
|
+
}
|
56
|
+
|
57
|
+
it 'returns a decimal representation' do
|
58
|
+
s = '1.234.567,89'
|
59
|
+
|
60
|
+
converter.raw(n).should eq(s)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'when precision is given' do
|
65
|
+
subject(:converter) {
|
66
|
+
Foraneus::Converters::Decimal.new(:precision => 2)
|
67
|
+
}
|
68
|
+
|
69
|
+
it 'x' do
|
70
|
+
n = BigDecimal.new('3.1')
|
71
|
+
converter.raw(n).should eq('3.10')
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'y' do
|
75
|
+
n = BigDecimal.new('3.145')
|
76
|
+
converter.raw(n).should eq('3.145')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|