foraneus 0.0.14 → 0.0.15

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,7 +1,7 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 6a1af4481bfbdeb0cc0aa78900c6b7f4512d7a21
4
- data.tar.gz: 58cd1c7f084558def0575754919263b6763ba17a
5
- SHA512:
6
- metadata.gz: 093a3fdc5eecea2934cd2ef01c88191bcf62fe317f61ed73519d8a77b4afcadd2ff96b5af17d4e5337e43da96bdd325861b6f94ca53d0a6642db6ffaf0aa5a03
7
- data.tar.gz: cbf2a485c1df7a4da036256ea27f6a8097f7433cb8b4bcd3e5c922e1ef985b2003ed6a5e442f3755af1f89a66da393efd6c80f314787f54c6d9767223304fd1f
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d581bebcc546182ffb84546ff4fb8ad667ee126f
4
+ data.tar.gz: 241b1dfc78a1837a6ec6404904ab1a4b1f6d3125
5
+ SHA512:
6
+ metadata.gz: 457b8493632fb86f01ea610b164f05df68c0f85f156ab26d3c7fe98ee62a2262c9a2281dd037f636ffb31fac42b49f68ad66386dcd264db5023134d9ef0fbe15
7
+ data.tar.gz: 4c668906d942e090e563b7ec8a8241c4cfa1cb42096bad58146c168aca89672cdd82b1a92c99896fd8bcf7af7c354d5a9e525fb7a32122f9900103fc4060d52d
@@ -10,13 +10,14 @@ require 'foraneus/converters/integer'
10
10
  require 'foraneus/converters/noop'
11
11
  require 'foraneus/converters/string'
12
12
  require 'foraneus/errors'
13
+ require 'foraneus/utils'
13
14
 
14
15
  # Foraneus base class used to declare a data set, aka 'form'.
15
16
  class Foraneus
16
17
 
17
18
  # @api private
18
19
  def initialize
19
- @_ = {}
20
+ @_ = {} # Hash that holds external representation data
20
21
  end
21
22
 
22
23
  # Declares a boolean field.
@@ -99,6 +100,11 @@ class Foraneus
99
100
  @fields ||= {}
100
101
  end
101
102
 
103
+ # Return the names of data and error accessors
104
+ #
105
+ # Returned hash contains the keys :data and :errors, where values are the proper accesor names
106
+ #
107
+ # @return [Hash]
102
108
  def self.accessors
103
109
  @accessors ||= {
104
110
  :data => :data,
@@ -106,11 +112,14 @@ class Foraneus
106
112
  }
107
113
  end
108
114
 
115
+ # Create a new instance while setting up data and error accessors
116
+ #
117
+ # @return [Foraneus]
109
118
  def self.create_instance
110
119
  instance = self.new
111
120
 
112
- __singleton_attr_reader(instance, :data, {})
113
- __singleton_attr_reader(instance, :errors, {})
121
+ Utils.singleton_attr_accessor(instance, :data, {})
122
+ Utils.singleton_attr_accessor(instance, :errors, {})
114
123
 
115
124
  instance
116
125
  end
@@ -122,24 +131,12 @@ class Foraneus
122
131
  # @return [Foraneus] An instance of a form.
123
132
  def self.parse(data = {})
124
133
  instance = self.create_instance
134
+ data = data.dup
125
135
 
126
- parsed_keys = []
136
+ instance.instance_variable_set(:@_, data.dup)
127
137
 
128
138
  fields.each do |field, converter|
129
- given_key = field
130
- v = data.fetch(given_key) do
131
- given_key = field.to_sym
132
- data.fetch(given_key, nil)
133
- end
134
-
135
- parsed_keys << given_key
136
- __parse_raw_datum(given_key, v, instance, converter)
137
- end
138
-
139
- data.each do |k, v|
140
- unless parsed_keys.include?(k)
141
- instance[k] = v
142
- end
139
+ __parse_field(data, field, converter, instance)
143
140
  end
144
141
 
145
142
  instance
@@ -152,16 +149,12 @@ class Foraneus
152
149
  # @return [Foraneus] An instance of a form.
153
150
  def self.raw(data = {})
154
151
  instance = self.create_instance
152
+ data = data.dup
155
153
 
156
- fields.each do |field, converter|
157
- given_key = field
158
-
159
- v = data.fetch(given_key) do
160
- given_key = field.to_sym
161
- data.fetch(given_key, nil)
162
- end
154
+ instance.send("#{self.accessors[:data]}=", data)
163
155
 
164
- __raw_datum(given_key, v, instance, converter)
156
+ fields.each do |field, converter|
157
+ __raw_field(data, field, converter, instance)
165
158
  end
166
159
 
167
160
  instance
@@ -174,8 +167,8 @@ class Foraneus
174
167
  if m.nil?
175
168
  @_
176
169
  else
177
- @_.fetch(m) do
178
- @_[m.to_s]
170
+ @_.fetch(m.to_s) do
171
+ @_[m.to_sym]
179
172
  end
180
173
  end
181
174
  end
@@ -198,100 +191,33 @@ class Foraneus
198
191
  @errors.empty?
199
192
  end
200
193
 
201
- # @api private
202
- #
203
- # Parses a value and assigns it to the corresponding field.
204
- #
205
- # It also registers errors if the conversion fails.
206
- #
207
- # @param [String, Symbol] k
208
- # @param [String] v
209
- # @param [Foraneus] foraneus
210
- # @param [Converter] converter
211
- def self.__parse_raw_datum(k, v, foraneus, converter)
212
- field = k.to_s
213
-
214
- foraneus[k] = v
215
-
216
- v = __parse(k, v, converter)
194
+ def self.__parse_field(data, field, converter, instance)
195
+ s, is_present = Utils.fetch(data, field)
217
196
 
218
- foraneus.send("#{field}=", v)
219
- foraneus.send(self.accessors[:data])[k] = v
197
+ v, error = Utils.parse_datum(field, s, converter)
220
198
 
221
- rescue
222
- error = Foraneus::Error.new($!.class.name, $!.message)
223
- foraneus.send(self.accessors[:errors])[k] = error
224
- end
225
- private_class_method :__parse_raw_datum
226
-
227
- # @api private
228
- #
229
- # Parses a raw value.
230
- #
231
- # @param [String, Symbol] field
232
- # @param [String] v Raw value.
233
- # @param converter
234
- #
235
- # @raise [KeyError] if converter requires a value but no one is given.
236
- #
237
- # @return [Object]
238
- def self.__parse(field, v, converter)
239
- if v == '' && converter.opts.fetch(:blanks_as_nil, true)
240
- v = nil
199
+ unless error
200
+ instance.send("#{field}=", v)
201
+ instance.send(self.accessors[:data])[field.to_sym] = v if is_present || converter.opts.include?(:default)
241
202
  end
242
203
 
243
- if v.nil? && converter.opts[:required]
244
- raise KeyError, "required parameter not found: #{field.inspect}"
245
- elsif v.nil?
246
- converter.opts[:default]
247
- else
248
- converter.parse(v)
249
- end
204
+ instance.send(self.accessors[:errors])[field.to_sym] = error if error
250
205
  end
251
- private_class_method :__parse
206
+ private_class_method :__parse_field
252
207
 
253
- # @api private
254
- #
255
- # Obtains a raw representation of a value and assigns it to the corresponding field.
256
- #
257
- # It also registers errors if the conversion fails.
258
- #
259
- # @param [String, Symbol] k
260
- # @param [String] v
261
- # @param [Foraneus] foraneus
262
- # @param [Converter] converter
263
- def self.__raw_datum(k, v, foraneus, converter)
264
- foraneus.send("#{k}=", v)
208
+ def self.__raw_field(data, field, converter, instance)
209
+ v, is_present = Utils.fetch(data, field)
210
+
211
+ instance.send("#{field}=", v)
265
212
 
266
213
  if v.nil?
267
214
  v = converter.opts[:default]
268
215
  end
269
216
 
270
- s = unless v.nil?
271
- converter.raw(v)
272
- end
273
-
274
- foraneus[k] = s
275
- foraneus.send(self.accessors[:data])[k] = v
276
- end
277
- private_class_method :__raw_datum
278
-
279
- # @api private
280
- #
281
- # Creates a singleton attribute reader on an instance.
282
- #
283
- # @param [Foraneus] instance
284
- # @param [Symbol] attribute
285
- # @param initial_value
286
- def self.__singleton_attr_reader(instance, attribute, initial_value = nil)
287
- spec = instance.class
217
+ s = Utils.raw_datum(v, converter)
288
218
 
289
- instance.singleton_class.send(:attr_reader, spec.accessors[attribute])
290
-
291
- instance.instance_exec do
292
- instance.instance_variable_set(:"@#{spec.accessors[attribute]}", initial_value)
293
- end
219
+ instance[field.to_sym] = s if is_present || converter.opts.include?(:default)
294
220
  end
295
- private_class_method :__singleton_attr_reader
221
+ private_class_method :__raw_field
296
222
 
297
223
  end
@@ -0,0 +1,86 @@
1
+ class Foraneus
2
+ module Utils
3
+
4
+ # Return the value of a key in the given hash and flag indicating whether the keys exists or not
5
+ #
6
+ # If the given key is not present then tries fetching key#to_sym
7
+ #
8
+ # @param [Hash] data
9
+ # @param [String] field
10
+ #
11
+ # @return [Object, Boolean]
12
+ def self.fetch(hash, key)
13
+ v = nil
14
+ is_present = true
15
+
16
+ v = hash.fetch(key) do
17
+ hash.fetch(key.to_sym) do
18
+ is_present = false
19
+ nil
20
+ end
21
+ end
22
+
23
+ [v, is_present]
24
+ end
25
+
26
+ # Parses a raw value.
27
+ #
28
+ # @param [String, Symbol] field
29
+ # @param [String] s Raw value.
30
+ # @param converter
31
+ #
32
+ # @raise [KeyError] if converter requires a value but no one is given.
33
+ #
34
+ # @return [Object, nil] when parsing succeeds
35
+ # @return [nil, Foraneus::Error] when parsing fails
36
+ def self.parse_datum(field, s, converter)
37
+ if s == '' && converter.opts.fetch(:blanks_as_nil, true)
38
+ s = nil
39
+ end
40
+
41
+ if s.nil? && converter.opts[:required]
42
+ raise KeyError, "required parameter not found: #{field.inspect}"
43
+ end
44
+
45
+ result = if s.nil?
46
+ converter.opts[:default]
47
+
48
+ else
49
+ converter.parse(s)
50
+ end
51
+
52
+ [result, nil]
53
+
54
+ rescue
55
+ error = Foraneus::Error.new($!.class.name, $!.message)
56
+
57
+ [nil, error]
58
+ end
59
+
60
+ # Obtains a raw representation of a value and assigns it to the corresponding field.
61
+ #
62
+ # @param [Object] v
63
+ # @param [Converter] converter
64
+ #
65
+ # @return [String]
66
+ def self.raw_datum(v, converter)
67
+ converter.raw(v) unless v.nil?
68
+ end
69
+
70
+ # Creates a singleton attribute accessor on an instance.
71
+ #
72
+ # @param [Foraneus] instance
73
+ # @param [Symbol] attribute
74
+ # @param initial_value
75
+ def self.singleton_attr_accessor(instance, attribute, initial_value = nil)
76
+ spec = instance.class
77
+
78
+ instance.singleton_class.send(:attr_accessor, spec.accessors[attribute])
79
+
80
+ instance.instance_exec do
81
+ instance.instance_variable_set(:"@#{spec.accessors[attribute]}", initial_value)
82
+ end
83
+ end
84
+
85
+ end
86
+ end
@@ -82,9 +82,10 @@ describe Foraneus do
82
82
 
83
83
  assert_equal 5, subject.delay
84
84
  assert_equal 5, subject.data[:delay]
85
+ assert_equal({ :delay => 5 }, subject.data)
85
86
 
86
87
  assert_equal '5', subject[:delay]
87
- assert_nil subject['delay']
88
+ assert_equal '5', subject['delay']
88
89
  assert_equal({ :delay => '5' }, subject[])
89
90
 
90
91
  assert subject.valid?
@@ -98,7 +99,8 @@ describe Foraneus do
98
99
  it 'parses given data' do
99
100
  assert_equal '5', subject['delay']
100
101
  assert_equal '5', subject[:delay]
101
- assert_equal 5, subject.data['delay']
102
+
103
+ assert_equal({ :delay => 5 }, subject.data)
102
104
 
103
105
  assert_equal({ 'delay' => '5' }, subject[])
104
106
  end
@@ -267,11 +269,7 @@ describe Foraneus do
267
269
 
268
270
  assert_equal 1, subject.delay
269
271
 
270
- assert_equal 1, subject.data[:delay]
271
-
272
- assert_nil subject[:delay]
273
-
274
- assert_nil subject[][:delay]
272
+ assert_equal({ :delay => 1}, subject.data)
275
273
 
276
274
  refute subject.errors.include?(:delay)
277
275
  end
@@ -289,6 +287,21 @@ describe Foraneus do
289
287
  assert_nil subject[:delay]
290
288
  end
291
289
  end
290
+
291
+ describe 'when missing optional field' do
292
+ let(:converter) { Foraneus::Converters::Integer.new(:required => false) }
293
+
294
+ subject { form_spec.parse }
295
+
296
+ it 'parses' do
297
+ assert subject.valid?
298
+
299
+ assert_nil subject.delay
300
+ refute_includes subject.data, :delay
301
+
302
+ refute_includes subject[], :delay
303
+ end
304
+ end
292
305
  end
293
306
  end
294
307
  end
@@ -303,7 +316,7 @@ describe Foraneus do
303
316
 
304
317
  assert_equal '5', subject[:delay]
305
318
 
306
- assert_equal '5', subject[][:delay]
319
+ assert_equal({ :delay => '5' }, subject[])
307
320
 
308
321
  assert subject.valid?
309
322
 
@@ -320,7 +333,7 @@ describe Foraneus do
320
333
 
321
334
  assert_equal '5', subject[:delay]
322
335
 
323
- assert_equal '5', subject[]['delay']
336
+ assert_equal({ :delay => '5' }, subject[])
324
337
 
325
338
  assert subject.valid?
326
339
 
@@ -349,11 +362,22 @@ describe Foraneus do
349
362
 
350
363
  it 'parses' do
351
364
  assert_nil subject.delay
365
+ refute_includes subject.data, :delay
352
366
 
353
367
  assert_equal '1', subject[:delay]
354
368
  assert_equal '1', subject[][:delay]
355
369
  end
356
370
  end
357
- end
358
371
 
372
+ describe 'with absent values' do
373
+ subject { form_spec.raw }
374
+
375
+ it 'parses' do
376
+ assert_nil subject.delay
377
+
378
+ assert_equal({}, subject.data)
379
+ assert_equal({}, subject[])
380
+ end
381
+ end
382
+ end
359
383
  end
metadata CHANGED
@@ -1,52 +1,63 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: foraneus
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.14
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.15
5
5
  platform: ruby
6
- authors:
6
+ authors:
7
7
  - Gianfranco Zas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
-
12
- date: 2014-12-04 00:00:00 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
11
+ date: 2015-04-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
15
14
  name: minitest
16
- prerelease: false
17
- requirement: &id001 !ruby/object:Gem::Requirement
18
- requirements:
19
- - &id002
20
- - ">="
21
- - !ruby/object:Gem::Version
22
- version: "0"
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
23
20
  type: :development
24
- version_requirements: *id001
25
- - !ruby/object:Gem::Dependency
26
- name: yard
27
21
  prerelease: false
28
- requirement: &id003 !ruby/object:Gem::Requirement
29
- requirements:
30
- - *id002
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: yard
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
31
34
  type: :development
32
- version_requirements: *id003
33
- - !ruby/object:Gem::Dependency
34
- name: kramdown
35
35
  prerelease: false
36
- requirement: &id004 !ruby/object:Gem::Requirement
37
- requirements:
38
- - *id002
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: kramdown
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
39
48
  type: :development
40
- version_requirements: *id004
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  description: Provides two way transformation mechanisms to external data.
42
56
  email: snmgian@gmail.com
43
57
  executables: []
44
-
45
58
  extensions: []
46
-
47
59
  extra_rdoc_files: []
48
-
49
- files:
60
+ files:
50
61
  - COPYING
51
62
  - COPYING.LESSER
52
63
  - README.md
@@ -60,6 +71,7 @@ files:
60
71
  - lib/foraneus/converters/noop.rb
61
72
  - lib/foraneus/converters/string.rb
62
73
  - lib/foraneus/errors.rb
74
+ - lib/foraneus/utils.rb
63
75
  - spec/lib/foraneus/converters/boolean_converter_spec.rb
64
76
  - spec/lib/foraneus/converters/date_converter_spec.rb
65
77
  - spec/lib/foraneus/converters/decimal_converter_spec.rb
@@ -70,42 +82,38 @@ files:
70
82
  - spec/lib/foraneus_spec.rb
71
83
  - spec/runner.rb
72
84
  - spec/spec_helper.rb
73
- - spec/spec_helper_its.rb
74
85
  homepage: https://github.com/snmgian/foraneus
75
- licenses:
86
+ licenses:
76
87
  - LGPL
77
88
  metadata: {}
78
-
79
89
  post_install_message:
80
90
  rdoc_options: []
81
-
82
- require_paths:
91
+ require_paths:
83
92
  - lib
84
- required_ruby_version: !ruby/object:Gem::Requirement
85
- requirements:
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
86
95
  - - ">="
87
- - !ruby/object:Gem::Version
96
+ - !ruby/object:Gem::Version
88
97
  version: 1.8.7
89
- required_rubygems_version: !ruby/object:Gem::Requirement
90
- requirements:
91
- - *id002
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
92
103
  requirements: []
93
-
94
104
  rubyforge_project:
95
105
  rubygems_version: 2.4.5
96
106
  signing_key:
97
107
  specification_version: 4
98
108
  summary: Transforms external data.
99
- test_files:
100
- - spec/lib/foraneus_spec.rb
109
+ test_files:
110
+ - spec/lib/foraneus/converters/float_converter_spec.rb
101
111
  - spec/lib/foraneus/converters/noop_converter_spec.rb
102
- - spec/lib/foraneus/converters/decimal_converter_spec.rb
103
112
  - spec/lib/foraneus/converters/date_converter_spec.rb
113
+ - spec/lib/foraneus/converters/decimal_converter_spec.rb
104
114
  - spec/lib/foraneus/converters/integer_converter_spec.rb
105
- - spec/lib/foraneus/converters/string_converter_spec.rb
106
- - spec/lib/foraneus/converters/float_converter_spec.rb
107
115
  - spec/lib/foraneus/converters/boolean_converter_spec.rb
108
- - spec/spec_helper.rb
109
- - spec/spec_helper_its.rb
116
+ - spec/lib/foraneus/converters/string_converter_spec.rb
117
+ - spec/lib/foraneus_spec.rb
110
118
  - spec/runner.rb
111
- has_rdoc:
119
+ - spec/spec_helper.rb
@@ -1,42 +0,0 @@
1
-
2
- require 'minitest/autorun'
3
- require 'minitest/spec'
4
- require 'minitest/unit'
5
-
6
- require 'foraneus'
7
-
8
- module MiniTest
9
- class Spec
10
- #module
11
-
12
- def self.its(getter, &block)
13
- block ||= proc { skip "(no tests defined)" }
14
-
15
- @specs ||= 0
16
- @specs += 1
17
-
18
- name = "test_%04d_%s" % [ @specs, getter ]
19
-
20
- define_method(name) {
21
- #&block
22
- case getter
23
- when Symbol, String
24
- expression = subject.public_send(getter)
25
- when Array
26
- expression = subject[*getter]
27
- end
28
-
29
- expression.instance_exec &block
30
- }
31
-
32
- self.children.each do |mod|
33
- mod.send :undef_method, name if mod.public_method_defined? name
34
- end
35
-
36
- name
37
- end
38
-
39
- #end
40
- end
41
- end
42
-