eapi 0.1.2 → 0.2.0

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