foraneus 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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
  - - ! '>='