pragma-decorator 1.1.0 → 1.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: 4ff5939aba8c33bfd6bce0dfe784392ec89b0905
4
- data.tar.gz: 24b7825e2c07df12ef69089d7ee854a1bcbcc408
3
+ metadata.gz: e8cbfb161f363349668460111a7fb2f5936b400a
4
+ data.tar.gz: 1e49a4456a7d4aaf2a01d217f3fb52538e49fa86
5
5
  SHA512:
6
- metadata.gz: cf9c5241c0107a425dbe86bd802f46ac25c698b219ace26187aa1b5a744ecf18fbbf230ea090f59799964e1c7c632980e2488f9c779a5bae25880f5f8d45ffb1
7
- data.tar.gz: 3e6a9cfbfaca8868c8f2f39a9be3978f2e5319c4f7b2e5ac7357413bc2372d83ca6450e0bf800e98e98fe1ab66b71005784c54fe111ce159e041823f89fbb0be
6
+ metadata.gz: ff52579a206fea38b5333c74b84589a579c5b1d0886f633848635fc61a28f6f178176ac609c7a0a53bff1683e173b6652a4628d54c767a3a86be00abbb763f37
7
+ data.tar.gz: 666eb32eb1ba858e3659ee403af8a40432ef623292f2a7e3ff0fc53ee2c9a023f0256f3ee30043d33c3d346c971c384751a798b124656adf27ed422e10e41815
data/.rubocop.yml CHANGED
@@ -85,3 +85,13 @@ Metrics/CyclomaticComplexity:
85
85
 
86
86
  Metrics/BlockLength:
87
87
  Enabled: false
88
+
89
+ Metrics/ClassLength:
90
+ Enabled: false
91
+
92
+ Style/GuardClause:
93
+ Enabled: false
94
+
95
+ Naming/FileName:
96
+ Exclude:
97
+ - 'pragma-decorator.gemspec'
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Pragma
3
4
  module Decorator
4
5
  module Association
@@ -20,6 +21,8 @@ module Pragma
20
21
  def initialize(reflection:, decorator:)
21
22
  @reflection = reflection
22
23
  @decorator = decorator
24
+
25
+ check_type_consistency
23
26
  end
24
27
 
25
28
  # Returns the associated object.
@@ -28,18 +31,52 @@ module Pragma
28
31
  def associated_object
29
32
  case reflection.options[:exec_context]
30
33
  when :decorated
31
- decorator.decorated.send(reflection.property)
34
+ model.public_send(reflection.property)
32
35
  when :decorator
33
- decorator.send(reflection.property)
36
+ decorator.public_send(reflection.property)
34
37
  end
35
38
  end
36
39
 
40
+ # Returns whether the association belongs to the model.
41
+ #
42
+ # @return [Boolean]
43
+ def model_context?
44
+ reflection.options[:exec_context].to_sym == :decorated
45
+ end
46
+
47
+ # Returns whether the association belongs to the decorator.
48
+ #
49
+ # @return [Boolean]
50
+ def decorator_context?
51
+ reflection.options[:exec_context].to_sym == :decorator
52
+ end
53
+
37
54
  # Returns the unexpanded value for the associated object (i.e. its +id+ property).
38
55
  #
39
56
  # @return [String]
40
57
  def unexpanded_value
41
- return unless associated_object
42
- associated_object.id
58
+ if decorator_context? || model_reflection.nil?
59
+ return associated_object&.public_send(associated_object.class.primary_key)
60
+ end
61
+
62
+ case reflection.type
63
+ when :belongs_to
64
+ model.public_send(model_reflection.foreign_key)
65
+ when :has_one
66
+ if model.association(reflection.property).loaded?
67
+ return associated_object&.public_send(associated_object.class.primary_key)
68
+ end
69
+
70
+ pk = model.public_send(model_reflection.active_record_primary_key)
71
+
72
+ model_reflection
73
+ .klass
74
+ .where(model_reflection.foreign_key => pk)
75
+ .pluck(model_reflection.klass.primary_key)
76
+ .first
77
+ else
78
+ associated_object&.public_send(associated_object.class.primary_key)
79
+ end
43
80
  end
44
81
 
45
82
  # Returns the expanded value for the associated object.
@@ -116,6 +153,36 @@ module Pragma
116
153
  reflection.options[:decorator]
117
154
  end
118
155
  end
156
+
157
+ def model
158
+ decorator.decorated
159
+ end
160
+
161
+ def model_reflection
162
+ # rubocop:disable Metrics/LineLength
163
+ @model_reflection ||= if Object.const_defined?('ActiveRecord') && model.is_a?(ActiveRecord::Base)
164
+ model.class.reflect_on_association(reflection.property)
165
+ end
166
+ # rubocop:enable Metrics/LineLength
167
+ end
168
+
169
+ def model_association_type
170
+ return unless model_reflection
171
+
172
+ if Object.const_defined?('ActiveRecord') && model.is_a?(ActiveRecord::Base)
173
+ model_reflection.macro
174
+ end
175
+ end
176
+
177
+ def check_type_consistency
178
+ return if !model_association_type || model_association_type == reflection.type
179
+
180
+ fail InconsistentTypeError.new(
181
+ decorator: decorator,
182
+ reflection: reflection,
183
+ model_type: model_association_type
184
+ )
185
+ end
119
186
  end
120
187
  end
121
188
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pragma
4
+ module Decorator
5
+ module Association
6
+ # This error is raised when an association's type is different from its type as reported by
7
+ # the model's reflection.
8
+ #
9
+ # @author Alessandro Desantis
10
+ class InconsistentTypeError < StandardError
11
+ # Initializes the error.
12
+ #
13
+ # @param decorator [Base] the decorator where the association is defined
14
+ # @param reflection [Reflection] the reflection of the inconsistent association
15
+ # @param model_type [Symbol|String] the real type of the association
16
+ def initialize(decorator:, reflection:, model_type:)
17
+ message = <<~MSG.tr("\n", ' ')
18
+ #{decorator.class}: Association #{reflection.property} is defined as #{model_type} on
19
+ the model, but as #{reflection.type} in the decorator.
20
+ MSG
21
+
22
+ super message
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Pragma
3
4
  module Decorator
4
5
  module Association
@@ -50,14 +51,14 @@ module Pragma
50
51
  @options = {
51
52
  expandable: false,
52
53
  render_nil: false,
53
- exec_context: :decorated
54
+ exec_context: :decorated,
54
55
  }.merge(options).tap do |opts|
55
56
  opts[:exec_context] = opts[:exec_context].to_sym
56
57
  end
57
58
  end
58
59
 
59
60
  def validate_options
60
- return if [:decorator, :decorated].include?(options[:exec_context])
61
+ return if %i[decorator decorated].include?(options[:exec_context])
61
62
 
62
63
  fail(
63
64
  ArgumentError,
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Pragma
3
4
  module Decorator
4
5
  module Association
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Pragma
3
4
  module Decorator
4
5
  # Adds association expansion to decorators.
@@ -63,11 +64,13 @@ module Pragma
63
64
  end
64
65
 
65
66
  def create_association_getter(property)
66
- class_eval <<~RUBY
67
+ code = <<~RUBY
67
68
  def _#{property}_association
68
69
  @association_bindings[:#{property}].render(user_options[:expand])
69
70
  end
70
71
  RUBY
72
+
73
+ class_eval code, __FILE__, __LINE__
71
74
  end
72
75
 
73
76
  def create_association_property(property_name)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'roar/decorator'
3
4
  require 'roar/json'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Pragma
3
4
  module Decorator
4
5
  # Supports rendering timestamps as UNIX times.
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Pragma
3
4
  module Decorator
4
5
  # Adds a +type+ property containing the machine-readable type of the represented object.
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Pragma
3
4
  module Decorator
4
- VERSION = '1.1.0'
5
+ VERSION = '1.2.0'
5
6
  end
6
7
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'roar'
3
4
 
4
5
  require 'pragma/decorator/version'
@@ -7,6 +8,7 @@ require 'pragma/decorator/association'
7
8
  require 'pragma/decorator/association/reflection'
8
9
  require 'pragma/decorator/association/binding'
9
10
  require 'pragma/decorator/association/unexpandable_error'
11
+ require 'pragma/decorator/association/inconsistent_type_error'
10
12
  require 'pragma/decorator/timestamp'
11
13
  require 'pragma/decorator/type'
12
14
 
@@ -1,4 +1,6 @@
1
- # coding: utf-8
1
+
2
+ # frozen_string_literal: true
3
+
2
4
  lib = File.expand_path('../lib', __FILE__)
3
5
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
6
  require 'pragma/decorator/version'
@@ -20,13 +22,13 @@ Gem::Specification.new do |spec|
20
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
23
  spec.require_paths = ['lib']
22
24
 
23
- spec.add_dependency 'roar', '~> 1.0'
24
25
  spec.add_dependency 'multi_json', '~> 1.12'
26
+ spec.add_dependency 'roar', '~> 1.0'
25
27
 
26
28
  spec.add_development_dependency 'bundler'
29
+ spec.add_development_dependency 'coveralls'
27
30
  spec.add_development_dependency 'rake'
28
31
  spec.add_development_dependency 'rspec'
29
32
  spec.add_development_dependency 'rubocop'
30
33
  spec.add_development_dependency 'rubocop-rspec'
31
- spec.add_development_dependency 'coveralls'
32
34
  end
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pragma-decorator
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Desantis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-23 00:00:00.000000000 Z
11
+ date: 2018-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: roar
14
+ name: multi_json
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '1.12'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: '1.12'
27
27
  - !ruby/object:Gem::Dependency
28
- name: multi_json
28
+ name: roar
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.12'
33
+ version: '1.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.12'
40
+ version: '1.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rake
56
+ name: coveralls
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rspec
70
+ name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rubocop
84
+ name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: rubocop-rspec
98
+ name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -109,7 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: coveralls
112
+ name: rubocop-rspec
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
@@ -146,6 +146,7 @@ files:
146
146
  - lib/pragma/decorator.rb
147
147
  - lib/pragma/decorator/association.rb
148
148
  - lib/pragma/decorator/association/binding.rb
149
+ - lib/pragma/decorator/association/inconsistent_type_error.rb
149
150
  - lib/pragma/decorator/association/reflection.rb
150
151
  - lib/pragma/decorator/association/unexpandable_error.rb
151
152
  - lib/pragma/decorator/base.rb
@@ -173,7 +174,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
174
  version: '0'
174
175
  requirements: []
175
176
  rubyforge_project:
176
- rubygems_version: 2.6.8
177
+ rubygems_version: 2.6.13
177
178
  signing_key:
178
179
  specification_version: 4
179
180
  summary: Convert your API resources into JSON with minimum hassle.