pragma-decorator 1.1.0 → 1.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: 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.