eapi 0.1.2 → 0.2.0

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
1
  ---
2
2
  SHA1:
3
- metadata.gz: f8a6da6f094409d07aa648318c1134b587bee426
4
- data.tar.gz: c9d3e9715481dc3d1be43324fef7f81e860f3f06
3
+ metadata.gz: 24226b6df180842850c926be63af60c33803e6e0
4
+ data.tar.gz: 1764202eb7a457a16bde2590b25909af05d4d17b
5
5
  SHA512:
6
- metadata.gz: 46a2d8ccee0b0ccd1ca44756b6e7b5a7ed89801c0fd0192fa58367b4a55136df17689dcf13b59f4311bbe76b168e1f3ae84c80092d976467ae249cbb9ca7a5fe
7
- data.tar.gz: 6e53f3f52a55fb714fbf48763f075afbb2bee60c77a40f72ed72b73cae1bab78025879b997362bf8b5036d1f15d5a4d5f7613955e32bf6b32a1f2a9657157a0b
6
+ metadata.gz: abef4e5a06756f1f32db42e60e0358451d524620ea0d7dc21af6f4929da5eea21f86a74a9930142164b219ba68ecb362cefe6f7115baffda67ba93a2477d7ec2
7
+ data.tar.gz: d67597321bb8c496167825f17b558c2e0e6e02b2bd75064eee1a7126146d2ffa0ecdb42742f5f912c19cce4ee45c5ef43e6d81158a5081dfbda353bab9960a09
@@ -8,7 +8,6 @@ addons:
8
8
 
9
9
  rvm:
10
10
  - 2.1.1
11
- - 2.0.0
12
11
 
13
12
  script: 'bundle exec rake spec'
14
13
 
@@ -17,4 +16,4 @@ notifications:
17
16
  recipients:
18
17
  - eturino@eturino.com
19
18
  on_failure: change
20
- on_success: never
19
+ on_success: never
data/README.md CHANGED
@@ -25,14 +25,15 @@ Or install it yourself as:
25
25
 
26
26
  ### Ruby version
27
27
 
28
- Works with ruby 2. Tested with MRI 2.1.1 and 2.0.0
28
+ Works with ruby 2.1, tested with MRI 2.1.1
29
29
 
30
30
  ### Gem dependencies
31
31
 
32
- This gem uses ActiveSupport (version 4) and also the ActiveModel Validations (version 4)
32
+ This gem uses ActiveSupport (version 4) and also the ActiveModel Validations (version 4). It also uses fluent_accessors gem.
33
33
 
34
34
  Extracted from the gemspec:
35
35
  ```
36
+ spec.add_dependency 'fluent_accessors', '~> 1'
36
37
  spec.add_dependency 'activesupport', '~> 4'
37
38
  spec.add_dependency 'activemodel', '~> 4'
38
39
  ```
@@ -41,11 +42,11 @@ spec.add_dependency 'activemodel', '~> 4'
41
42
 
42
43
  ### including EAPI into your class
43
44
 
44
- Just include the module `Eapi::Common` into your class.
45
+ Just include the module `Eapi::Item` into your class.
45
46
 
46
47
  ```ruby
47
48
  class MyTestKlass
48
- include Eapi::Common
49
+ include Eapi::Item
49
50
 
50
51
  property :something
51
52
  end
@@ -59,7 +60,7 @@ For now any unrecognised property in the hash will be ignored. This may change i
59
60
 
60
61
  ```ruby
61
62
  class MyTestKlass
62
- include Eapi::Common
63
+ include Eapi::Item
63
64
 
64
65
  property :something
65
66
  end
@@ -78,14 +79,14 @@ To show this feature and all the combinations for method names, we'll use the 2
78
79
 
79
80
  ```ruby
80
81
  class MyTestKlassOutside
81
- include Eapi::Common
82
+ include Eapi::Item
82
83
 
83
84
  property :something
84
85
  end
85
86
 
86
87
  module Somewhere
87
88
  class TestKlassInModule
88
- include Eapi::Common
89
+ include Eapi::Item
89
90
 
90
91
  property :something
91
92
  end
@@ -116,7 +117,7 @@ We define properties in our class with the instruction `property` as shown:
116
117
 
117
118
  ```ruby
118
119
  class MyTestKlass
119
- include Eapi::Common
120
+ include Eapi::Item
120
121
 
121
122
  property :one
122
123
  property :two
@@ -169,13 +170,15 @@ x.one # => :fluent
169
170
  res.equal? x # => true
170
171
  ```
171
172
 
172
- ### Convert to hashes: `to_h` and `create_hash`
173
+ ### Convert to hashes: `render`, `to_h` and `create_hash`
173
174
 
174
- All Eapi classes respond to `to_h` and return a hash, as it is the main purpose of this gem. It will execute any validation (see property definition), and if everything is ok, it will convert it to a simple hash structure.
175
+ All Eapi classes respond to `render` and return a hash (for `Item` classes) or an array (for `List` classes), as it is the main purpose of this gem. It will execute any validation (see property definition), and if everything is ok, it will convert it to a simple hash structure.
176
+
177
+ `Item` classes will invoke `render` when receiving `to_h`, while `List` classes will do the same when receiving `to_a`
175
178
 
176
179
  #### Methods involved
177
180
 
178
- Inside, `to_h` will call `valid?`, raise an error of type `Eapi::Errors::InvalidElementError` if something is not right, and if everything is ok it will call `create_hash`.
181
+ Inside, `render` will call `valid?`, raise an error of type `Eapi::Errors::InvalidElementError` if something is not right, and if everything is ok it will call `create_hash`.
179
182
 
180
183
  The `create_hash` method will create a hash with the properties as keys. Each value will be "converted".
181
184
 
@@ -203,13 +206,13 @@ class ComplexValue
203
206
  end
204
207
 
205
208
  class ExampleEapi
206
- include Eapi::Common
209
+ include Eapi::Item
207
210
 
208
211
  property :something, required: true
209
212
  property :other
210
213
  end
211
214
 
212
- # TESTING `to_h`
215
+ # TESTING `render`
213
216
 
214
217
  list = Set.new [
215
218
  OpenStruct.new(a: 1, 'b' => 2),
@@ -218,7 +221,9 @@ list = Set.new [
218
221
  ]
219
222
 
220
223
  eapi = ExampleEapi.new something: list, other: ComplexValue.new
221
- eapi.to_h # =>
224
+
225
+ # same as eapi.to_h
226
+ eapi.render # =>
222
227
  # {
223
228
  # something: [
224
229
  # {a: 1, b: 2},
@@ -249,7 +254,7 @@ example:
249
254
 
250
255
  ```ruby
251
256
  class TestKlass
252
- include Eapi::Common
257
+ include Eapi::Item
253
258
 
254
259
  property :something, required: true
255
260
  end
@@ -268,7 +273,7 @@ example:
268
273
 
269
274
  ```ruby
270
275
  class TestKlass
271
- include Eapi::Common
276
+ include Eapi::Item
272
277
 
273
278
  property :something, type: Hash
274
279
  end
@@ -283,7 +288,7 @@ Also, if a type is specified, then a `init_property_name` method is created that
283
288
 
284
289
  ```ruby
285
290
  class TestKlass
286
- include Eapi::Common
291
+ include Eapi::Item
287
292
 
288
293
  property :something, type: Hash
289
294
  end
@@ -298,7 +303,7 @@ A symbol or a string can also be specified as class name in `type` option, and i
298
303
 
299
304
  ```ruby
300
305
  class TestKlass
301
- include Eapi::Common
306
+ include Eapi::Item
302
307
 
303
308
  property :something, type: "Hash"
304
309
  end
@@ -319,7 +324,7 @@ example:
319
324
 
320
325
  ```ruby
321
326
  class TestKlass
322
- include Eapi::Common
327
+ include Eapi::Item
323
328
 
324
329
  property :something, validate_with: ->(record, attr, value) do
325
330
  record.errors.add(attr, "must pass my custom validation") unless value == :valid_val
@@ -338,7 +343,7 @@ All other ActiveModel::Validations can be used:
338
343
 
339
344
  ```ruby
340
345
  class TestKlass
341
- include Eapi::Common
346
+ include Eapi::Item
342
347
 
343
348
  property :something
344
349
  validates :something, numericality: true
@@ -360,7 +365,7 @@ You can see (but not edit) the definition of a property calling the `definition_
360
365
 
361
366
  ```ruby
362
367
  class TestKlass
363
- include Eapi::Common
368
+ include Eapi::Item
364
369
 
365
370
  property :something, type: Hash, unrecognised_option: 1
366
371
  end
@@ -384,7 +389,7 @@ A property marked as `multiple` will be initialised with an empty array. If no t
384
389
 
385
390
  ```ruby
386
391
  class TestKlass
387
- include Eapi::Common
392
+ include Eapi::Item
388
393
 
389
394
  property :something, multiple: true
390
395
  end
@@ -398,7 +403,7 @@ If the property is `nil` when `add_property_name` is called, then it will call `
398
403
 
399
404
  ```ruby
400
405
  class TestKlass
401
- include Eapi::Common
406
+ include Eapi::Item
402
407
 
403
408
  property :something, multiple: true
404
409
  end
@@ -431,7 +436,7 @@ class MyCustomList
431
436
  end
432
437
 
433
438
  class TestKlass
434
- include Eapi::Common
439
+ include Eapi::Item
435
440
 
436
441
  property :p1, multiple: true
437
442
  property :p2, type: Array
@@ -453,7 +458,7 @@ We can also specify `validate_element_with` option, and it will act the same as
453
458
 
454
459
  ```ruby
455
460
  class TestKlass
456
- include Eapi::Common
461
+ include Eapi::Item
457
462
 
458
463
  property :something, multiple: true, element_type: Hash
459
464
  property :other, multiple: true, validate_element_with: ->(record, attr, value) do
@@ -480,6 +485,60 @@ eapi.other [:valid_val]
480
485
  eapi.valid? # => true
481
486
  ```
482
487
 
488
+ ### `List` classes
489
+
490
+ An Eapi `List` is to an Array as an Eapi `Item` is to a Hash.
491
+
492
+ It will render itself into an array of elements. It can store a list of elements that will be validated and rendered.
493
+
494
+ It works using an internal list of elements, to whom it delegates most of the behaviour. Its interface is compatible with an Array, including ActiveSupport methods.
495
+
496
+ #### accessor to internal element list: `_list`
497
+
498
+ The internal list of elements of an Eapi `List` object can be accessed using the `_list` method, that is always an `Array`.
499
+
500
+ #### fluent adder: `add`
501
+
502
+ Similar to the `set_x` methods for properties, this method will add an element to the internal list and return `self`.
503
+
504
+ #### elements definition: `elements`
505
+
506
+ Similar to the `property` macro to define a property and its requirements, `List` classes can set the definition to be used for its elements using the macro `elements`.
507
+
508
+ The options for that definition is:
509
+
510
+ * `required`: it will provoke the list validation to fail if there is at least 1 element in the list
511
+ * `unique`: it will provoke the list validation to fail if there are duplicated elements in the list
512
+ * `element_type` or `type`: it will provoke the list validation to fail if an element does not complies with the given type validation (see type validation on `Item`)
513
+ * `validate_element_with` or `validate_with`: it will execute the given callable object to validate each element, similar to the `validate_element_with` option in the property definition.
514
+
515
+ #### example
516
+
517
+ ```ruby
518
+ class MyListKlass
519
+ include Eapi::List
520
+
521
+ elements unique: true
522
+ end
523
+
524
+ l = MyListKlass.new
525
+
526
+ # fluent adder
527
+ l.add(1).add(2).add(3)
528
+
529
+ # internal list accessor
530
+ l._list # => [1, 2, 3]
531
+
532
+ # render method (same as #to_a)
533
+ l.render # => [1, 2, 3]
534
+
535
+ l.valid? # => true
536
+
537
+ l.add(1)
538
+
539
+ l.valid? # => false
540
+ ```
541
+
483
542
  ### Pose as other types
484
543
 
485
544
  An Eapi class can poses as other types, for purposes of `type` checking in a property definition. We use the class method `is` for this.
@@ -492,7 +551,7 @@ example:
492
551
 
493
552
  ```ruby
494
553
  class SuperTestKlass
495
- include Eapi::Common
554
+ include Eapi::Item
496
555
  end
497
556
 
498
557
  class TestKlass < SuperTestKlass
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency "pry-stack_explorer"
29
29
  spec.add_development_dependency "pry-doc"
30
30
 
31
+ spec.add_dependency 'fluent_accessors', '~> 1'
31
32
  spec.add_dependency 'activesupport', '~> 4'
32
33
  spec.add_dependency 'activemodel', '~> 4'
33
34
  end
@@ -1,15 +1,18 @@
1
+ require 'fluent_accessors'
1
2
  require 'active_support/all'
2
3
  require 'active_model'
3
4
 
4
5
  require 'eapi/version'
5
6
  require 'eapi/errors'
6
7
  require 'eapi/children'
7
- require 'eapi/multiple'
8
- require 'eapi/definition_runner'
8
+ require 'eapi/multiple_value'
9
+ require 'eapi/definition_runners'
9
10
  require 'eapi/type_checker'
10
11
  require 'eapi/methods'
11
12
  require 'eapi/value_converter'
12
13
  require 'eapi/common'
14
+ require 'eapi/item'
15
+ require 'eapi/list'
13
16
 
14
17
 
15
18
  module Eapi
@@ -29,6 +32,8 @@ module Eapi
29
32
  def self.extended(mod)
30
33
  mod.class_eval <<-CODE
31
34
  Common = Eapi::Common
35
+ Item = Eapi::Item
36
+ List = Eapi::List
32
37
  Children = Eapi::Children
33
38
  CODE
34
39
  Eapi.add_method_missing mod
@@ -3,46 +3,29 @@ module Eapi
3
3
  def self.add_features(klass)
4
4
  Eapi::Children.append klass
5
5
  klass.send :include, ActiveModel::Validations
6
+ klass.send :include, Eapi::Common::Basic
6
7
  klass.send :include, Eapi::Methods::Properties::InstanceMethods
7
8
  klass.send :include, Eapi::Methods::Types::InstanceMethods
8
9
 
9
10
  klass.send :extend, ClassMethods
10
11
  end
11
12
 
12
- def self.extended(mod)
13
- def mod.included(klass)
14
- Eapi::Common.add_features klass
13
+ module Basic
14
+ def initialize(** properties)
15
+ properties.each do |k, v|
16
+ normal_setter = Eapi::Methods::Names.setter k
17
+ #TODO: what to do with unrecognised properties
18
+ send normal_setter, v if respond_to? normal_setter
19
+ end
15
20
  end
16
- end
17
-
18
- def self.included(klass)
19
- Eapi::Common.add_features klass
20
- end
21
21
 
22
- def initialize(** properties)
23
- properties.each do |k, v|
24
- normal_setter = Eapi::Methods::Names.setter k
25
- #TODO: what to do with unrecognised properties
26
- send normal_setter, v if respond_to? normal_setter
27
- end
28
- end
29
-
30
- def to_h
31
- raise Eapi::Errors::InvalidElementError, "errors: #{errors.full_messages}, self: #{self.inspect}" unless valid?
32
-
33
- create_hash
34
- end
35
-
36
- def create_hash
37
- {}.tap do |hash|
38
- self.class.properties.each do |prop|
39
- val = Eapi::ValueConverter.convert_value(get(prop))
40
- hash[prop] = val unless val.nil?
41
- end
22
+ def validate!
23
+ raise Eapi::Errors::InvalidElementError, "errors: #{errors.full_messages}, self: #{self.inspect}" unless valid?
42
24
  end
43
25
  end
44
26
 
45
27
  module ClassMethods
28
+ include FluentAccessors
46
29
  include Eapi::Methods::Accessor
47
30
  include Eapi::Methods::Types::ClassMethods
48
31
  include Eapi::Methods::Properties::ClassMethods
@@ -0,0 +1,3 @@
1
+ require 'eapi/definition_runners/runner'
2
+ require 'eapi/definition_runners/property'
3
+ require 'eapi/definition_runners/list'
@@ -0,0 +1,60 @@
1
+ module Eapi
2
+ module DefinitionRunners
3
+
4
+
5
+ class List < Struct.new(:klass, :definition)
6
+ def run
7
+ run_validations
8
+ end
9
+
10
+ private
11
+ def run_validations
12
+ run_required
13
+ run_validate_element_type
14
+ run_validate_element_with
15
+ run_validate_uniqueness
16
+ end
17
+
18
+ def run_validate_uniqueness
19
+ if unique?
20
+ Runner.unique klass: klass, field: :_list
21
+ end
22
+ end
23
+
24
+ def run_validate_element_with
25
+ if validate_element_with
26
+ Runner.validate_element_with klass: klass, field: :_list, validate_element_with: validate_element_with
27
+ end
28
+ end
29
+
30
+ def run_validate_element_type
31
+ if element_type
32
+ Runner.validate_element_type(klass: klass, field: :_list, element_type: element_type)
33
+ end
34
+ end
35
+
36
+ def run_required
37
+ if required?
38
+ Runner.required(klass: klass, field: :_list)
39
+ end
40
+ end
41
+
42
+ def required?
43
+ definition.fetch(:required, false)
44
+ end
45
+
46
+ def unique?
47
+ definition.fetch(:unique, false)
48
+ end
49
+
50
+ def validate_element_with
51
+ definition.fetch(:validate_element_with, nil) || definition.fetch(:validate_with, nil)
52
+ end
53
+
54
+ def element_type
55
+ definition.fetch(:element_type, nil) || definition.fetch(:type, nil)
56
+ end
57
+ end
58
+
59
+ end
60
+ end