entity_schema 0.1.2 → 0.1.4

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -18
  3. data/CHANGELOG.md +7 -0
  4. data/Gemfile.lock +1 -1
  5. data/lib/entity_schema/class_methods.rb +1 -1
  6. data/lib/entity_schema/dsl.rb +33 -11
  7. data/lib/entity_schema/fields/abstract.rb +18 -35
  8. data/lib/entity_schema/fields/builders/belongs_to.rb +20 -65
  9. data/lib/entity_schema/fields/collection.rb +7 -3
  10. data/lib/entity_schema/fields/contracts/belongs_to.rb +15 -0
  11. data/lib/entity_schema/fields/contracts/collection.rb +11 -0
  12. data/lib/entity_schema/fields/contracts/common.rb +16 -0
  13. data/lib/entity_schema/fields/contracts/contract.rb +54 -0
  14. data/lib/entity_schema/fields/contracts/fk_belongs_to.rb +11 -0
  15. data/lib/entity_schema/fields/contracts/object.rb +17 -0
  16. data/lib/entity_schema/fields/contracts/object_belongs_to.rb +11 -0
  17. data/lib/entity_schema/fields/contracts/property.rb +13 -0
  18. data/lib/entity_schema/fields/fk_belongs_to.rb +8 -0
  19. data/lib/entity_schema/fields/object.rb +7 -6
  20. data/lib/entity_schema/fields/object_belongs_to.rb +2 -0
  21. data/lib/entity_schema/fields/property.rb +6 -9
  22. data/lib/entity_schema/fields/specifications/abstract.rb +89 -0
  23. data/lib/entity_schema/fields/specifications/belongs_to.rb +22 -0
  24. data/lib/entity_schema/fields/specifications/collection.rb +14 -0
  25. data/lib/entity_schema/fields/specifications/common.rb +24 -0
  26. data/lib/entity_schema/fields/specifications/fk_belongs_to.rb +15 -0
  27. data/lib/entity_schema/fields/specifications/object.rb +40 -0
  28. data/lib/entity_schema/fields/specifications/object_belongs_to.rb +13 -0
  29. data/lib/entity_schema/fields/specifications/property.rb +19 -0
  30. data/lib/entity_schema/instance_methods.rb +2 -1
  31. data/lib/entity_schema/setup_field.rb +36 -0
  32. data/lib/entity_schema/version.rb +1 -1
  33. metadata +19 -11
  34. data/.rubocop_todo.yml +0 -26
  35. data/lib/entity_schema/dsl_helper.rb +0 -26
  36. data/lib/entity_schema/fields/builders/.rubocop.yml +0 -7
  37. data/lib/entity_schema/fields/builders/abstract.rb +0 -116
  38. data/lib/entity_schema/fields/builders/collection.rb +0 -20
  39. data/lib/entity_schema/fields/builders/fk_belongs_to.rb +0 -21
  40. data/lib/entity_schema/fields/builders/object.rb +0 -56
  41. data/lib/entity_schema/fields/builders/object_belongs_to.rb +0 -17
  42. data/lib/entity_schema/fields/builders/property.rb +0 -33
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EntitySchema
4
+ module Fields
5
+ module Specifications
6
+ # Transform raw valid options to usefull options
7
+ class Abstract
8
+ def initialize(name, owner_name, raw_options)
9
+ @options = transform_options(name: name,
10
+ owner_name: owner_name,
11
+ **raw_options)
12
+ end
13
+
14
+ def [](key)
15
+ options.fetch(key, nil)
16
+ end
17
+
18
+ def to_h
19
+ options.dup
20
+ end
21
+
22
+ def method_missing(key, *_args, **_opts)
23
+ return options[key] if options.key?(key)
24
+ root = without_predicate(key)
25
+ return options[root] if bool_key?(root)
26
+ super
27
+ end
28
+
29
+ def respond_to_missing?(key)
30
+ options.key?(key) || bool_key?(without_predicate(key))
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :options
36
+
37
+ # Hook for ancestors
38
+ def transform_options(_options)
39
+ new_strict_hash
40
+ end
41
+
42
+ def bool_key?(key)
43
+ [true, false].include? options.fetch(key, nil)
44
+ end
45
+
46
+ def without_predicate(key)
47
+ key.to_s.delete('?').to_sym
48
+ end
49
+
50
+ def new_strict_hash
51
+ Hash.new do |h, k|
52
+ raise "Gem works wrong: missed option `#{k.inspect}` called. Options is: #{h.keys}"
53
+ end
54
+ end
55
+
56
+ def find(*alternatives)
57
+ alternatives.compact.first
58
+ end
59
+
60
+ # eql(hash, a: 1, b: [1, 2, :value])
61
+ def eql(input, pairs)
62
+ pairs.each do |k, values|
63
+ Array(values).each do |v|
64
+ return true if input[k] == v
65
+ end
66
+ end
67
+ nil
68
+ end
69
+
70
+ def callable(subject)
71
+ subject if subject.respond_to?(:call)
72
+ end
73
+
74
+ def owner_meth(option)
75
+ return unless option.is_a?(Symbol)
76
+ owner.method(option)
77
+ end
78
+
79
+ def truth(subject)
80
+ subject == true ? true : nil
81
+ end
82
+
83
+ def to_bool(subject)
84
+ subject ? true : false
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common'
4
+ require_relative 'fk_belongs_to'
5
+ require_relative 'object_belongs_to'
6
+
7
+ module EntitySchema
8
+ module Fields
9
+ module Specifications
10
+ class BelongsTo < Object
11
+ private
12
+
13
+ def transform_options(opts)
14
+ super.merge!(
15
+ fk: opts[:fk] || :"#{opts[:name]}_id",
16
+ pk: opts[:pk] || :id
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common'
4
+ require_relative 'object'
5
+ require_relative '../collection'
6
+
7
+ module EntitySchema
8
+ module Fields
9
+ module Specifications
10
+ class Collection < Specifications::Object
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'abstract'
4
+
5
+ module EntitySchema
6
+ module Fields
7
+ module Specifications
8
+ class Common < Abstract
9
+ private
10
+
11
+ def transform_options(input)
12
+ super.merge!(
13
+ name: input[:name],
14
+ src_key: input[:key] || input[:name],
15
+ owner_name: input[:owner_name],
16
+ public_getter: !eql(input, getter: :private, private: [:getter, true]),
17
+ public_setter: !eql(input, setter: :private, private: [:setter, true]),
18
+ predicate: false
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common'
4
+
5
+ module EntitySchema
6
+ module Fields
7
+ module Specifications
8
+ class FkBelongsTo < Common
9
+ def transform_options(_name, _owner, _options)
10
+ super.merge!(predicate: false)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common'
4
+ require_relative '../object'
5
+
6
+ module EntitySchema
7
+ module Fields
8
+ module Specifications
9
+ class Object < Common
10
+ private
11
+
12
+ def transform_options(o)
13
+ super.merge!(
14
+ mapper: find(callable(o[:mapper]),
15
+ owner_meth(o[:mapper]),
16
+ mapper(o[:map_to], o[:map_method]),
17
+ default_mapper),
18
+ serializer: find(o[:serializer],
19
+ serializer(o))
20
+ )
21
+ end
22
+
23
+ def mapper(map_to, map_method)
24
+ return if map_to.nil?
25
+ map_method ||= :new
26
+ ->(hash) { map_to.public_send(map_method, hash) }
27
+ end
28
+
29
+ def default_mapper
30
+ ->(hash) { hash }
31
+ end
32
+
33
+ def serializer(opts)
34
+ map_method = opts[:serialize] || :to_h
35
+ ->(object) { object.public_send(map_method) }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common'
4
+ require_relative '../object_belongs_to'
5
+
6
+ module EntitySchema
7
+ module Fields
8
+ module Specifications
9
+ class ObjectBelongsTo < Specifications::Object
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common'
4
+
5
+ module EntitySchema
6
+ module Fields
7
+ module Specifications
8
+ class Property < Common
9
+ private
10
+
11
+ def transform_options(o)
12
+ super.merge!(
13
+ predicate: to_bool(o[:predicate])
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EntitySchema
4
- # TODO: doc
4
+ # methods that will be available for interact
5
+ # with Entity instances
5
6
  module InstanceMethods
6
7
  def initialize(params = EMPTY_HASH)
7
8
  update_attributes(params)
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EntitySchema
4
+ # Define or redefine methods for work with Entity fields
5
+ module SetupField
6
+ def setup_field(field, spec)
7
+ entity_schema.add_field(field)
8
+
9
+ setup_getter(field)
10
+ setup_setter(field)
11
+ setup_predicate(field) if spec.predicate?
12
+ end
13
+
14
+ def setup_getter(field)
15
+ m = field.name
16
+ define_method(m) { field.get(self) }
17
+ public(m) if field.public_getter?
18
+ private(m) unless field.public_getter?
19
+ end
20
+
21
+ def setup_setter(field)
22
+ m = :"#{field.name}="
23
+ define_method(m) { |value| field.set(self, value) }
24
+ public(m) if field.public_setter?
25
+ private(m) unless field.public_setter?
26
+ end
27
+
28
+ def setup_predicate(field)
29
+ m = :"#{field.name}?"
30
+ remove_method(m) if method_defined?(m)
31
+ define_method(m) { field.get(self) }
32
+ public(m) if field.public_getter?
33
+ private(m) unless field.public_getter?
34
+ end
35
+ end
36
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EntitySchema
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: entity_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Captain Philipp
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-21 00:00:00.000000000 Z
11
+ date: 2018-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -190,7 +190,6 @@ files:
190
190
  - ".overcommit.yml"
191
191
  - ".rspec"
192
192
  - ".rubocop.yml"
193
- - ".rubocop_todo.yml"
194
193
  - ".ruby-gemset"
195
194
  - ".ruby-version"
196
195
  - ".travis.yml"
@@ -208,24 +207,33 @@ files:
208
207
  - lib/entity_schema.rb
209
208
  - lib/entity_schema/class_methods.rb
210
209
  - lib/entity_schema/dsl.rb
211
- - lib/entity_schema/dsl_helper.rb
212
210
  - lib/entity_schema/fields/abstract.rb
213
- - lib/entity_schema/fields/builders/.rubocop.yml
214
- - lib/entity_schema/fields/builders/abstract.rb
215
211
  - lib/entity_schema/fields/builders/belongs_to.rb
216
- - lib/entity_schema/fields/builders/collection.rb
217
- - lib/entity_schema/fields/builders/fk_belongs_to.rb
218
- - lib/entity_schema/fields/builders/object.rb
219
- - lib/entity_schema/fields/builders/object_belongs_to.rb
220
- - lib/entity_schema/fields/builders/property.rb
221
212
  - lib/entity_schema/fields/collection.rb
213
+ - lib/entity_schema/fields/contracts/belongs_to.rb
214
+ - lib/entity_schema/fields/contracts/collection.rb
215
+ - lib/entity_schema/fields/contracts/common.rb
216
+ - lib/entity_schema/fields/contracts/contract.rb
217
+ - lib/entity_schema/fields/contracts/fk_belongs_to.rb
218
+ - lib/entity_schema/fields/contracts/object.rb
219
+ - lib/entity_schema/fields/contracts/object_belongs_to.rb
220
+ - lib/entity_schema/fields/contracts/property.rb
222
221
  - lib/entity_schema/fields/fk_belongs_to.rb
223
222
  - lib/entity_schema/fields/object.rb
224
223
  - lib/entity_schema/fields/object_belongs_to.rb
225
224
  - lib/entity_schema/fields/observer_belongs_to.rb
226
225
  - lib/entity_schema/fields/property.rb
226
+ - lib/entity_schema/fields/specifications/abstract.rb
227
+ - lib/entity_schema/fields/specifications/belongs_to.rb
228
+ - lib/entity_schema/fields/specifications/collection.rb
229
+ - lib/entity_schema/fields/specifications/common.rb
230
+ - lib/entity_schema/fields/specifications/fk_belongs_to.rb
231
+ - lib/entity_schema/fields/specifications/object.rb
232
+ - lib/entity_schema/fields/specifications/object_belongs_to.rb
233
+ - lib/entity_schema/fields/specifications/property.rb
227
234
  - lib/entity_schema/instance_methods.rb
228
235
  - lib/entity_schema/schema.rb
236
+ - lib/entity_schema/setup_field.rb
229
237
  - lib/entity_schema/version.rb
230
238
  homepage: https://github.com/CaptainPhilipp/entity_schema
231
239
  licenses:
data/.rubocop_todo.yml DELETED
@@ -1,26 +0,0 @@
1
- # This configuration was generated by
2
- # `rubocop --auto-gen-config`
3
- # on 2018-08-20 00:34:58 +0300 using RuboCop version 0.55.0.
4
- # The point is for the user to remove these configuration records
5
- # one by one as the offenses are removed from the code base.
6
- # Note that changes in the inspected code, or installation of new
7
- # versions of RuboCop, may require this file to be generated again.
8
-
9
- # Offense count: 14
10
- Style/Documentation:
11
- Exclude:
12
- - 'lib/entity_schema.rb'
13
- - 'lib/entity_schema/class_methods.rb'
14
- - 'lib/entity_schema/dsl_helper.rb'
15
- - 'lib/entity_schema/fields/abstract.rb'
16
- - 'lib/entity_schema/fields/builders/abstract.rb'
17
- - 'lib/entity_schema/fields/builders/belongs_to.rb'
18
- - 'lib/entity_schema/fields/builders/collection.rb'
19
- - 'lib/entity_schema/fields/builders/fk_belongs_to.rb'
20
- - 'lib/entity_schema/fields/builders/object.rb'
21
- - 'lib/entity_schema/fields/builders/object_belongs_to.rb'
22
- - 'lib/entity_schema/fields/builders/property.rb'
23
- - 'lib/entity_schema/fields/collection.rb'
24
- - 'lib/entity_schema/fields/object.rb'
25
- - 'lib/entity_schema/fields/property.rb'
26
- - 'lib/entity_schema/instance_methods.rb'
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EntitySchema
4
- # TODO: remove this shit
5
- # TODO: doc
6
- module DslHelper
7
- def setup_field(field)
8
- remove_method(field.name) if method_defined?(field.name)
9
- remove_method(field.predicate_name) if method_defined?(field.predicate_name)
10
- remove_method(field.setter_name) if method_defined?(field.setter_name)
11
-
12
- entity_schema.add_field field
13
-
14
- define_method(field.name) { field.get(self) }
15
- private(field.name) unless field.public_getter?
16
-
17
- if field.predicate?
18
- define_method(field.predicate_name) { field.get(self) }
19
- private(field.predicate_name) unless field.public_getter?
20
- end
21
-
22
- define_method(field.setter_name) { |value| field.set(self, value) }
23
- private(field.setter_name) unless field.public_setter?
24
- end
25
- end
26
- end
@@ -1,7 +0,0 @@
1
- inherit_from: ../../../../.rubocop.yml
2
-
3
- Metrics/AbcSize:
4
- Max: 20
5
-
6
- Metrics/LineLength:
7
- Max: 130
@@ -1,116 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'singleton'
4
- require_relative '../property'
5
-
6
- module EntitySchema
7
- module Fields
8
- module Builders
9
- # TODO: doc
10
- # Todo: refactor overweight class:
11
- # Responsibilities:
12
- # - options with strict contract and meaningfull exceptions,
13
- # - options transformation,
14
- # - building object,
15
- # building default mappers/serializers
16
- # refactor to Specification, Builder,
17
- # or to ParamsObject, Specification, Builder
18
- class Abstract
19
- include Singleton
20
-
21
- def self.call(*args)
22
- instance.call(*args)
23
- end
24
-
25
- def call(name, owner, options)
26
- options = substitute_callable_with_methods(options, owner)
27
- opts = extract_options(options)
28
- guard_unknown_options!(options, name)
29
- create_field(name, owner, opts)
30
- end
31
-
32
- private
33
-
34
- def extract_options(o)
35
- {
36
- key: check!(:key, o, [Symbol, nil]),
37
- getter: check!(:getter, o, [:private, nil]),
38
- setter: check!(:setter, o, [:private, nil]),
39
- private: check!(:private, o, [true, false, :getter, :setter, nil])
40
- }
41
- end
42
-
43
- def create_field(name, owner, opts)
44
- field_klass.new(name, owner.to_s, **create_field_params(opts, name))
45
- end
46
-
47
- # rubocop:disable Metrics/AbcSize:
48
- def create_field_params(o, name)
49
- {
50
- src_key: first_of(o[:key], name),
51
- public_getter: !first_of(true_(o[:getter] == :private), true_(o[:private] == :getter), true_(o[:private]), false),
52
- public_setter: !first_of(true_(o[:setter] == :private), true_(o[:private] == :setter), true_(o[:private]), false)
53
- }
54
- end
55
- # rubocop:enable Metrics/AbcSize:
56
-
57
- # :nocov:
58
- def field_klass
59
- raise NotImplementedError
60
- end
61
- # :nocov:
62
-
63
- # TODO: test #substitute_callable_with_methods
64
- def substitute_callable_with_methods(options, owner)
65
- options.dup.tap do |opts|
66
- opts[:serializer] = owner.method(opts[:serializer]) if opts[:serializer].is_a?(Symbol)
67
- opts[:mapper] = owner.method(opts[:mapper]) if opts[:mapper].is_a?(Symbol)
68
- end
69
- end
70
-
71
- # Helpers
72
-
73
- # rubocop:disable Naming/UncommunicativeMethodParamName
74
- def check!(key, h, allowed)
75
- value = h.delete(key)
76
- return value if allowed.any? do |v|
77
- v.is_a?(Class) ? value.is_a?(v) : value == v
78
- end
79
- raise ArgumentError, "option `#{key}:` must be in #{allowed}, but '#{value.inspect}'"
80
- end
81
- # rubocop:enable Naming/UncommunicativeMethodParamName
82
-
83
- # rubocop:disable Naming/UncommunicativeMethodParamName
84
- def check_ducktype!(key, h, methods)
85
- value = h.delete(key)
86
- return value if value.nil? || methods.all? { |m| value.respond_to?(m) }
87
- raise ArgumentError, "option `#{key}:` (#{value.inspect}) must respond to #{methods}"
88
- end
89
- # rubocop:enable Naming/UncommunicativeMethodParamName
90
-
91
- def first_of(*alternatives)
92
- alternatives.compact.first
93
- end
94
-
95
- def true_(value)
96
- value == true ? true : nil
97
- end
98
-
99
- def not_bool(value)
100
- case value
101
- when true, false then nil
102
- else value
103
- end
104
- end
105
-
106
- def to_bool(value)
107
- value ? true : false
108
- end
109
-
110
- def guard_unknown_options!(opts, name)
111
- raise "Unknown options given to `#{name}:` #{opts.inspect}" if opts.any?
112
- end
113
- end
114
- end
115
- end
116
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'abstract'
4
- require_relative 'object'
5
- require_relative '../collection'
6
-
7
- module EntitySchema
8
- module Fields
9
- module Builders
10
- # TODO: doc
11
- class Collection < Builders::Object
12
- private
13
-
14
- def field_klass
15
- Fields::Collection
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'abstract'
4
- require_relative '../fk_belongs_to'
5
-
6
- module EntitySchema
7
- module Fields
8
- module Builders
9
- # TODO: doc
10
- class FkBelongsTo < Abstract
11
- def create_field_params(o, name)
12
- super.merge!(predicate: false)
13
- end
14
-
15
- def field_klass
16
- Fields::FkBelongsTo
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'abstract'
4
- require_relative '../object'
5
-
6
- module EntitySchema
7
- module Fields
8
- module Builders
9
- # TODO: doc
10
- class Object < Abstract
11
- private
12
-
13
- # rubocop:disable Naming/UncommunicativeMethodParamName
14
- def extract_options(h)
15
- super.merge!(
16
- mapper: check_ducktype!(:mapper, h, [:call]),
17
- map_to: check!(:map_to, h, [Class, nil]),
18
- map_method: check!(:map_method, h, [Symbol, nil]),
19
- serializer: check_ducktype!(:serializer, h, [:call]),
20
- serialize: check!(:serialize, h, [Symbol, nil])
21
- )
22
- end
23
- # rubocop:enable Naming/UncommunicativeMethodParamName
24
-
25
- # TODO: test default_mapper, :mapper, :serializer
26
- def create_field_params(opts, name)
27
- super.merge!(
28
- mapper: first_of(opts[:mapper], build_mapper(opts), default_mapper),
29
- serializer: first_of(opts[:serializer], build_serializer(opts))
30
- )
31
- end
32
-
33
- def build_mapper(opts)
34
- return if opts[:map_to].nil?
35
-
36
- map_to = opts[:map_to]
37
- map_method = opts[:map_method] || :new
38
- ->(hash) { map_to.public_send(map_method, hash) }
39
- end
40
-
41
- def default_mapper
42
- ->(hash) { hash }
43
- end
44
-
45
- def build_serializer(opts)
46
- map_method = opts[:serialize] || :to_h
47
- ->(object) { object.public_send(map_method) }
48
- end
49
-
50
- def field_klass
51
- Fields::Object
52
- end
53
- end
54
- end
55
- end
56
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'object'
4
- require_relative '../object_belongs_to'
5
-
6
- module EntitySchema
7
- module Fields
8
- module Builders
9
- # TODO: doc
10
- class ObjectBelongsTo < Builders::Object
11
- def field_klass
12
- Fields::ObjectBelongsTo
13
- end
14
- end
15
- end
16
- end
17
- end