foraneus 0.0.6 → 0.0.7

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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MTdlYTI4OGY2Y2M4N2I3ODAxOTUyOThjYjYyYzA1MDlkNWMyZDliNg==
4
+ ZWMwYTU4OWRiZmI3YWMyYzVjYTc3OTc1YzJiOTUzZDM4YmU5YzZjNw==
5
5
  data.tar.gz: !binary |-
6
- OWM3NWRlYzIyZGEzMzYyNDVmMGEzMWZiYWIzMzY2YmI4NWY0MjhmMQ==
6
+ Mjc1YzUwODZhMTRiZmFhNTcxZjljYTQ3YzY1Nzk3NDA3Y2YyOTkyZQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MmQyNTdlNmFmNjNiNGM4MWIxYjcyMmExNWIxNDQxODA0MTdkNzFiMGFhMTVk
10
- M2E3ZWVhNzRmM2Q5ZDBkOGU3OTEzZDVjMzU1YTk3NGRhZTEyYWRkNDU3Yzc3
11
- Njc2N2Y0Mjk5NWYzNTBmM2UwNWUxNjgxMTVhMjk0YzNjNWZiZWU=
9
+ MjY2MmFlYmQ2MzhlMzBhOWM0MTE0ZWQ1N2ZmZDI4MmVhMzkxMzA5Nzg0NmY4
10
+ MzM1YjJmNzNiNzQ0YWU4MTY4ZDcxNTkzNjMzZTdjMjY5ZTdiNDY4ODJlYjdh
11
+ YWRhOWZmNTY0NTBmMDhiMTIyNjk4ZTU4M2ZmODI2NjMwM2ZhZDM=
12
12
  data.tar.gz: !binary |-
13
- YmUyYjQyZDNjZWI1NzllOTNhZTVkZjZmMjBiZDkyMjFhOTQ5OGE1MmU4NTYx
14
- MTYzYjMwMWY4OTAwY2YzODQzNzg1YTJhMDE2MTYxNmFmYTQ1ZjYxNzBlZGM3
15
- ZjU3ZjMzMGJjNWQ2Y2IwNTY1YmJkZDU5ZGU4N2NlYjBhNzFhMmE=
13
+ ZmRmZGI3NjFiODYzOGU1NDNjMGUwMTQ1NTkxODUzNGYwZmYzNzQxZWY0ZTY2
14
+ NjA4NjZmMjQxYTY5ZGJkNzQwOWYyMGYxN2UxNmVhYzgzYzQ5MzI4ZTZlNTA3
15
+ YTZhNTUyYWUwZjAwODE4YzBiZThkM2M3NWI1NWNkODg4YjAxMzk=
data/README.md CHANGED
@@ -51,17 +51,6 @@ raw and parsed data.
51
51
  form[] # => { :delay => '5', :duration => '2.14' }
52
52
  ```
53
53
 
54
- - When no data:
55
-
56
- ``` ruby
57
- form = MyForm.new
58
- ```
59
-
60
- ``` ruby
61
- form.delay # => nil
62
- form[:delay] # => nil
63
- ```
64
-
65
54
  ## Declaration
66
55
 
67
56
  Declare source classes by inheriting from `Foraneus` base class.
@@ -85,6 +74,16 @@ noop, and string.
85
74
  When no converter is passed to `.field`, Foraneus::Converters::Noop is assigned to the declared
86
75
  field.
87
76
 
77
+ ## Instantiation
78
+
79
+ Foraneus instances can be obtained by calling two methods: `parse` and `raw`.
80
+
81
+ Use `.parse` when:
82
+ - data is coming from outside of the system, like an HTTP request.
83
+
84
+ Use `.raw` when:
85
+ - data is coming from the inside of the system, like a business layer.
86
+
88
87
  ## Converters
89
88
 
90
89
  Converters have two interrelated responsibilities:
@@ -122,6 +121,7 @@ Valid instance:
122
121
  ```
123
122
 
124
123
  Invalid one:
124
+
125
125
  ``` ruby
126
126
  form = MyForm.parse(:delay => 'INVALID')
127
127
 
@@ -134,10 +134,9 @@ Invalid one:
134
134
  `#errors` is a map in which keys correspond to field names, and values are instances of
135
135
  `Foraneus::Error`.
136
136
 
137
- The name of the exception raised by `#parse` is to the error's `key` attribute, and the exception's
137
+ The name of the exception raised by `#parse` is the error's `key` attribute, and the exception's
138
138
  message is added to the error's `message` attribute.
139
139
 
140
-
141
140
  Data coming from the inside is assumed to be valid, so `.raw` won't return an instance having
142
141
  errors neither being invalid.
143
142
 
@@ -157,6 +156,16 @@ Tests are written in RSpec. To run them all just execute the following from your
157
156
  rspec
158
157
  ```
159
158
 
159
+ ## Code documentation
160
+
161
+ Documentation is written in Yard. To see it in a browser, execute this command:
162
+
163
+ ``` shell
164
+ yard server --reload
165
+ ```
166
+
167
+ Then point the browser to `http://localhost:8808/`.
168
+
160
169
  ## Badges
161
170
 
162
171
  [![Build Status](https://travis-ci.org/snmgian/foraneus.svg?branch=master)](https://travis-ci.org/snmgian/foraneus) [![Code Climate](https://codeclimate.com/github/snmgian/foraneus.png)](https://codeclimate.com/github/snmgian/foraneus)
@@ -1,7 +1,14 @@
1
1
  class Foraneus
2
2
  module Converters
3
3
 
4
+ # Boolean converter.
5
+ #
6
+ # When parsing, the string 'true' is converted to true, otherwise false is returned.
7
+ #
8
+ # When converting to a raw value, a true value => 'true', a false value => 'false'.
4
9
  class Boolean
10
+
11
+ # @return [Boolean]
5
12
  def parse(s)
6
13
  if s == 'true'
7
14
  true
@@ -7,10 +7,13 @@ class Foraneus
7
7
 
8
8
  DEFAULT_FORMAT = '%Y-%m-%d'
9
9
 
10
+ # @param [Hash] opts
11
+ # @option opts [String] format Date format.
10
12
  def initialize(opts = {})
11
13
  @format = opts[:format] || DEFAULT_FORMAT
12
14
  end
13
15
 
16
+ # return [Date]
14
17
  def parse(s)
15
18
  ::Date.strptime(s, @format)
16
19
  end
@@ -4,21 +4,30 @@ class Foraneus
4
4
  module Converters
5
5
 
6
6
  class Decimal
7
- DEFAULT_DELIMITER = ','
8
7
  DEFAULT_SEPARATOR = '.'
9
8
 
10
9
  DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
11
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.
12
15
  def initialize(opts = {})
13
- @delimiter = opts[:delimiter] || DEFAULT_DELIMITER
14
- @separator = opts[:separator] || DEFAULT_SEPARATOR
16
+ @delimiter = opts[:delimiter]
15
17
  @precision = opts[:precision]
18
+ @separator = opts[:separator] || DEFAULT_SEPARATOR
16
19
  end
17
20
 
21
+ # @return [BigDecimal]
18
22
  def parse(s)
19
23
  parts = s.split(@separator)
20
24
 
21
- integer_part = (parts[0] || '0').gsub(@delimiter, '')
25
+ integer_part = (parts[0] || '0')
26
+
27
+ if @delimiter
28
+ integer_part.gsub!(@delimiter, '')
29
+ end
30
+
22
31
  fractional_part = parts[1] || '0'
23
32
 
24
33
  BigDecimal.new("#{integer_part}.#{fractional_part}")
@@ -31,7 +40,9 @@ class Foraneus
31
40
  right = add_trailing_zeros(right, @precision - right.length)
32
41
  end
33
42
 
34
- left.gsub!(DELIMITED_REGEX) { "#{$1}#{@delimiter}" }
43
+ if @delimiter
44
+ left.gsub!(DELIMITED_REGEX) { "#{$1}#{@delimiter}" }
45
+ end
35
46
 
36
47
  "#{left}#{@separator}#{right}"
37
48
  end
@@ -7,12 +7,17 @@ class Foraneus
7
7
 
8
8
  DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
9
9
 
10
+ # @param [Hash] opts
11
+ # @option opts [String] delimiter Thousands delimiter.
12
+ # @option opts [String] separator Decimal separator.
13
+ # @option opts [Integer] precision Minimum precision.
10
14
  def initialize(opts = {})
11
15
  @delimiter = opts[:delimiter]
12
16
  @precision = opts[:precision]
13
17
  @separator = opts[:separator] || DEFAULT_SEPARATOR
14
18
  end
15
19
 
20
+ # @return [Float]
16
21
  def parse(s)
17
22
  if s == ''
18
23
  raise ArgumentError, 'invalid value for Float(): ""'
@@ -4,10 +4,13 @@ class Foraneus
4
4
  class Integer
5
5
  DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
6
6
 
7
+ # @param [Hash] opts
8
+ # @option opts [String] delimiter Thousands delimiter.
7
9
  def initialize(opts = {})
8
10
  @delimiter = opts[:delimiter]
9
11
  end
10
12
 
13
+ # @return [Integer]
11
14
  def parse(s)
12
15
  s = s.gsub(@delimiter, '') if @delimiter
13
16
 
@@ -1,7 +1,12 @@
1
1
  class Foraneus
2
2
  module Converters
3
3
 
4
+ # Noop converter.
5
+ #
6
+ # It does not perform any conversion at all. Useful when its needed to have a field but
7
+ # conversion is handled at another level.
4
8
  class Noop
9
+ # @return [Object]
5
10
  def parse(o)
6
11
  o
7
12
  end
@@ -2,6 +2,8 @@ class Foraneus
2
2
  module Converters
3
3
 
4
4
  class String
5
+
6
+ # @return [String]
5
7
  def parse(s)
6
8
  s.to_s
7
9
  end
data/lib/foraneus.rb CHANGED
@@ -7,58 +7,87 @@ require_relative 'foraneus/converters/noop'
7
7
  require_relative 'foraneus/converters/string'
8
8
  require_relative 'foraneus/errors'
9
9
 
10
- # Foraneus is library for parsing external data.
11
- #
12
- # It allows to define value_sets that specify how the external data is structured
13
- # and how it should be parsed.
10
+ # Foraneus base class used to declare a data set, aka 'form'.
14
11
  class Foraneus
15
12
 
13
+
14
+ # @return [Hash] Parsed data.
16
15
  attr_accessor :data
17
16
 
18
- def initialize(data = {})
17
+ # @api private
18
+ def initialize
19
19
  @data = {}
20
20
  @raw_data = {}
21
21
 
22
22
  @errors = {}
23
-
24
- self.class.send(:__raw, self, data)
25
23
  end
26
24
 
25
+ # Declares a boolean field.
26
+ #
27
+ # @param [Symbol] name The name of the field.
27
28
  def self.boolean(name)
28
29
  converter = Foraneus::Converters::Boolean.new
29
30
  field(name, converter)
30
31
  end
31
32
 
33
+ # Declares a date field.
34
+ #
35
+ # @param [Symbol] name The name of the field.
36
+ # @param (see Foraneus::Converters::Date#initialize)
32
37
  def self.date(name, *args)
33
38
  converter = Foraneus::Converters::Date.new(*args)
34
39
  field(name, converter)
35
40
  end
36
41
 
42
+ # Declares a decimal field.
43
+ #
44
+ # @param [Symbol] name The name of the field.
45
+ # @param (see Foraneus::Converters::Decimal#initialize)
37
46
  def self.decimal(name, *args)
38
47
  converter = Foraneus::Converters::Decimal.new(*args)
39
48
  field(name, converter)
40
49
  end
41
50
 
42
- def self.float(name)
43
- converter = Foraneus::Converters::Float.new
51
+ # Declares a float field.
52
+ #
53
+ # @param [Symbol] name The name of the field.
54
+ # @param (see Foraneus::Converters::Float#initialize)
55
+ def self.float(name, *args)
56
+ converter = Foraneus::Converters::Float.new(*args)
44
57
  field(name, converter)
45
58
  end
46
59
 
47
- def self.integer(name)
48
- converter = Foraneus::Converters::Integer.new
60
+ # Declares an integer field.
61
+ #
62
+ # @param [Symbol] name The name of the field.
63
+ # @param (see Foraneus::Converters::Integer#initialize)
64
+ def self.integer(name, *args)
65
+ converter = Foraneus::Converters::Integer.new(*args)
49
66
  field(name, converter)
50
67
  end
51
68
 
69
+ # Declares a noop field.
70
+ #
71
+ # @param [Symbol] name The name of the field.
52
72
  def self.noop(name)
53
73
  converter = Foraneus::Converters::Noop.new
54
74
  field(name, converter)
55
75
  end
56
76
 
77
+ # Declares a string field.
78
+ #
79
+ # @param [Symbol] name The name of the field.
57
80
  def self.string(name)
58
81
  converter = Foraneus::Converters::String.new
59
82
  field(name, converter)
60
83
  end
61
84
 
85
+ # Declares a field.
86
+ #
87
+ # When no converter is given, noop is assigned.
88
+ #
89
+ # @param [Symbol] name The name of the field.
90
+ # @param [#parse, #raw] converter The converter.
62
91
  def self.field(name, converter = nil)
63
92
  converter ||= Foraneus::Converters::Noop.new
64
93
 
@@ -66,15 +95,21 @@ class Foraneus
66
95
  self.send(:attr_accessor, name)
67
96
  end
68
97
 
98
+ # Map of fields and their corresponding converters.
99
+ #
100
+ # @return [Hash<String, Converter>]
69
101
  def self.fields
70
102
  @fields ||= {}
71
103
  end
72
104
 
105
+ # Parses data coming from an external source.
106
+ #
107
+ # @param [Hash<Symbol, String>] raw_data
108
+ #
109
+ # @return [Foraneus] An instance of a form.
73
110
  def self.parse(raw_data)
74
111
  instance = self.new
75
112
 
76
- parsed_data = {}
77
-
78
113
  raw_data.each do |k, v|
79
114
  __parse_raw_datum(instance, k, v)
80
115
  end
@@ -82,37 +117,14 @@ class Foraneus
82
117
  instance
83
118
  end
84
119
 
85
- # @param [Foraneus] foraneus
86
- # @param [String, Symbol] k
87
- # @param [String] v
88
- def self.__parse_raw_datum(foraneus, k, v)
89
- field = k.to_s
90
- converter = fields[field]
91
-
92
- return unless converter
93
-
94
- foraneus[k] = v
95
-
96
- unless v.nil?
97
- v = converter.parse(v)
98
- end
99
-
100
- foraneus.send("#{field}=", v)
101
- foraneus.data[k] = v
102
-
103
- rescue
104
- error = Foraneus::Error.new($!.class.name, $!.message)
105
- foraneus.instance_variable_get(:@errors)[k] = error
106
- end
107
- private_class_method :__parse_raw_datum
108
-
120
+ # Converts data into an external representation.
121
+ #
122
+ # @param [Hash<Symbol, Object>] data
123
+ #
124
+ # @return [Foraneus] An instance of a form.
109
125
  def self.raw(data)
110
126
  instance = self.new
111
127
 
112
- __raw(instance, data)
113
- end
114
-
115
- def self.__raw(instance, data)
116
128
  data.each do |k, v|
117
129
  next unless fields.has_key?(k.to_s)
118
130
  instance.send("#{k}=", v)
@@ -130,8 +142,10 @@ class Foraneus
130
142
 
131
143
  instance
132
144
  end
133
- private_class_method :__raw
134
145
 
146
+ # @return [Hash] raw data when m == nil.
147
+ # @return [Array<Error>] errors when m == :errors.
148
+ # @return [String] raw data value for the field m.
135
149
  def [](m = nil)
136
150
  if m == :errors
137
151
  @errors
@@ -144,11 +158,49 @@ class Foraneus
144
158
  end
145
159
  end
146
160
 
161
+ # @api private
162
+ #
163
+ # Sets a raw value.
164
+ #
165
+ # @param [Symbol] k Field name.
166
+ # @param [String] v Raw value.
147
167
  def []=(k, v)
148
168
  @raw_data[k] = v
149
169
  end
150
170
 
171
+ # Returns true if no conversion errors occurred. false otherwise.
151
172
  def valid?
152
173
  @errors.empty?
153
174
  end
175
+
176
+ # @api private
177
+ #
178
+ # Parses a raw value and assigns it to the corresponding field.
179
+ #
180
+ # It also registers errors if the conversion fails.
181
+ #
182
+ # @param [Foraneus] foraneus
183
+ # @param [String, Symbol] k
184
+ # @param [String] v
185
+ def self.__parse_raw_datum(foraneus, k, v)
186
+ field = k.to_s
187
+ converter = fields[field]
188
+
189
+ return unless converter
190
+
191
+ foraneus[k] = v
192
+
193
+ unless v.nil?
194
+ v = converter.parse(v)
195
+ end
196
+
197
+ foraneus.send("#{field}=", v)
198
+ foraneus.data[k] = v
199
+
200
+ rescue
201
+ error = Foraneus::Error.new($!.class.name, $!.message)
202
+ foraneus.instance_variable_get(:@errors)[k] = error
203
+ end
204
+ private_class_method :__parse_raw_datum
205
+
154
206
  end
@@ -44,7 +44,7 @@ describe Foraneus::Converters::Decimal do
44
44
  let(:n) { BigDecimal.new('1234567.89') }
45
45
 
46
46
  it 'returns a decimal representation' do
47
- s = '1,234,567.89'
47
+ s = '1234567.89'
48
48
 
49
49
  converter.raw(n).should eq(s)
50
50
  end
@@ -10,28 +10,6 @@ describe Foraneus do
10
10
  end
11
11
  }
12
12
 
13
- describe '.new' do
14
- subject(:form) { form_spec.new }
15
-
16
- its(:delay) { should be_nil }
17
-
18
- its([:delay]) { should be_nil }
19
-
20
- its(:data) { should be_empty }
21
-
22
- its([]) { should be_empty }
23
-
24
- context 'when initial data' do
25
- subject(:form) { form_spec.new(:delay => 5) }
26
-
27
- its(:delay) { should eq(5) }
28
- its([:delay]) { should eq('5') }
29
-
30
- its(:data) { should include(:delay => 5) }
31
- its([]) { should include(:delay => '5') }
32
- end
33
- end
34
-
35
13
  describe '.parse' do
36
14
  context 'with parseable data' do
37
15
  subject(:form) { form_spec.parse(:delay => '5') }
metadata CHANGED
@@ -1,17 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foraneus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gianfranco Zas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-19 00:00:00.000000000 Z
11
+ date: 2014-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 2.14.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 2.14.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: redcarpet
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
15
43
  requirement: !ruby/object:Gem::Requirement
16
44
  requirements:
17
45
  - - ! '>='