presentability 0.2.0 → 0.3.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
  SHA256:
3
- metadata.gz: f5b0aae4df8ff0ef130bbcc9704f2f44a9b109dee48cc530db6abdfd0733cbd4
4
- data.tar.gz: d149966c13d352f89c2f437c8ed251d63520ec33287c920e8ff7c1cd43eeb0e4
3
+ metadata.gz: ff4d9944824eaaa9ef6bc0d5e2b02879e83c481f2db9a39fe6c6ebc6f947dd7f
4
+ data.tar.gz: 4ccd0e65bdaae2504bf6edad1df4aab25698d5290b740028c5f5dc7c78732302
5
5
  SHA512:
6
- metadata.gz: 906172259081cb4c871975c6e8096bfcd7d8a2434903cc8bef9562b9b18c11af889ef1733372d46c94420008baf5821499d19e6708c75224abd962febabc0515
7
- data.tar.gz: 5d2c5691ee59ba2526755a3a2eab49547d093fa1d2fbedad4163a78ea35b8acc4dc74d20f0e16a90d7b9af3cbedd9a043c68f3b402f8197ea40031984fc4773b
6
+ metadata.gz: cae40ce72cd721000c47cff537ba2a2ac6635fc27205f79d81548471efda66b499c9aadd8eab97049a457dbd1c784e20ec5cd01805a57c511e1da808517c5ab8
7
+ data.tar.gz: 73ccbe66aeeed78447ae7cb91a0bb9cdbe95325d834e6fcfc6baaa4c96103cfb03efa4ef55f3718098ad021f211c17d5365f2e528b0dc5e846570ff6bec3407d
checksums.yaml.gz.sig CHANGED
Binary file
data/History.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # Release History for presentability
2
2
 
3
3
  ---
4
+ ## v0.3.0 [2022-12-16] Michael Granger <ged@faeriemud.org>
5
+
6
+ Improvements:
7
+
8
+ - Rework to use a more flexible exposure mechanism
9
+ - Allows `nil` and `false` as exposed values
10
+ - Allows declaring an exposure with a block
11
+
4
12
 
5
13
  ## v0.2.0 [2022-12-06] Michael Granger <ged@faeriemud.org>
6
14
 
@@ -69,14 +69,50 @@ class Presentability::Presenter
69
69
 
70
70
  ### Set up an exposure that will delegate to the attribute of the subject with
71
71
  ### the given +name+.
72
- def self::expose( name, **options )
72
+ def self::expose( name, **options, &block )
73
+ name = name.to_sym
73
74
  options = DEFAULT_EXPOSURE_OPTIONS.merge( options )
74
75
 
75
- self.log.debug "Setting up exposure %p %p" % [ name, options ]
76
+ self.define_method( name, &block ) if block
77
+
78
+ unless self.instance_methods( true ).include?( name )
79
+ method_body = self.generate_expose_method( name, **options )
80
+ define_method( name, &method_body )
81
+ end
82
+
83
+ self.log.debug "Setting up exposure %p, options = %p" % [ name, options ]
76
84
  self.exposures[ name ] = options
77
85
  end
78
86
 
79
87
 
88
+ ### Generate the body an exposure method that delegates to a method with the
89
+ ### same +name+ on its subject.
90
+ def self::generate_expose_method( name, **options )
91
+ self.log.debug "Generating a default delegation exposure method for %p" % [ name ]
92
+ return lambda do
93
+ return self.subject.send( __method__ )
94
+ end
95
+ end
96
+
97
+
98
+ ### Method definition hook -- hook up new methods with the same name as an exposure
99
+ ### to its :call option.
100
+ def self::method_added( method_name )
101
+ super
102
+
103
+ return unless self.exposures
104
+
105
+ if self.exposures.key?( method_name )
106
+ self.log.debug "Exposing %p via a new presenter method." % [ method_name ]
107
+ self.exposures[ method_name ][ :call ] = self.instance_method( method_name )
108
+ end
109
+ end
110
+
111
+
112
+ #
113
+ # Instance methods
114
+ #
115
+
80
116
  ### Create a new Presenter for the given +subject+.
81
117
  def initialize( subject, options={} )
82
118
  @subject = subject
@@ -104,11 +140,7 @@ class Presentability::Presenter
104
140
 
105
141
  self.class.exposures.each do |name, exposure_options|
106
142
  next if self.skip_exposure?( name )
107
-
108
- value = self.expose_via_delegation( name, exposure_options ) ||
109
- self.expose_via_presenter_method( name, exposure_options ) or
110
- raise NoMethodError, "can't expose %p -- no such attribute exists" % [name]
111
-
143
+ value = self.method( name ).call
112
144
  result[ name.to_sym ] = value
113
145
  end
114
146
 
@@ -143,27 +175,5 @@ class Presentability::Presenter
143
175
  end
144
176
 
145
177
 
146
- ### Attempt to expose the attribute with the given +name+ via delegation to the
147
- ### subject's method of the same name. Returns +nil+ if no such method exists.
148
- def expose_via_delegation( name, options={} )
149
- self.log.debug "Trying to expose %p via delegation to %p" % [ name, self.subject ]
150
-
151
- return nil unless self.subject.respond_to?( name )
152
-
153
- return self.subject.send( name )
154
- end
155
-
156
-
157
- ### Attempt to expose the attribute with the given +name+ via a method on the presenter
158
- ### of the same name. Returns +nil+ if no such method exists.
159
- def expose_via_presenter_method( name, options={} )
160
- self.log.debug "Trying to expose %p via presenter method" % [ name ]
161
-
162
- return nil unless self.respond_to?( name )
163
-
164
- meth = self.method( name )
165
- return meth.call
166
- end
167
-
168
178
  end # class Presentability::Presenter
169
179
 
@@ -72,7 +72,7 @@ module Presentability
72
72
 
73
73
 
74
74
  # Package version
75
- VERSION = '0.2.0'
75
+ VERSION = '0.3.0'
76
76
 
77
77
 
78
78
  # Automatically load subordinate components
@@ -37,14 +37,22 @@ RSpec.describe Presentability do
37
37
  @lastname = lastname
38
38
  @email = email
39
39
  @password = password
40
+ @is_admin = false
40
41
  end
41
42
 
42
- attr_accessor :firstname, :lastname, :email, :password
43
+ attr_accessor :firstname, :lastname, :email, :password, :is_admin
43
44
  end
44
45
  end
45
46
 
46
47
  let( :entity_instance ) { entity_class.new }
47
- let( :other_entity_instance ) { entity_class.new }
48
+ let( :other_entity_instance ) do
49
+ other_entity_class.new(
50
+ Faker::Name.first_name,
51
+ Faker::Name.last_name,
52
+ Faker::Internet.email,
53
+ Faker::Internet.password
54
+ )
55
+ end
48
56
 
49
57
 
50
58
  describe "an extended module" do
@@ -75,7 +83,7 @@ RSpec.describe Presentability do
75
83
  end
76
84
 
77
85
 
78
- it "can effect more complex exposures be declaring presenter methods" do
86
+ it "can define more complex exposures by declaring presenter methods" do
79
87
  extended_module.presenter_for( entity_class ) do
80
88
  expose :foo
81
89
  expose :bar
@@ -91,6 +99,56 @@ RSpec.describe Presentability do
91
99
  end
92
100
 
93
101
 
102
+ it "calls an exposure's block if it has one" do
103
+ extended_module.presenter_for( entity_class ) do
104
+ expose :foo
105
+ expose :bar
106
+ expose :id do
107
+ self.subject.object_id
108
+ end
109
+ end
110
+
111
+ expect( extended_module.present(entity_instance) ).
112
+ to eq({ foo: 1, bar: 'two', id: entity_instance.object_id })
113
+ end
114
+
115
+
116
+ it "exposes `false' values correctly" do
117
+ extended_module.presenter_for( other_entity_class ) do
118
+ expose :firstname
119
+ expose :lastname
120
+ expose :email
121
+ expose :is_admin
122
+ end
123
+
124
+ other_entity_instance.is_admin = false
125
+
126
+ expect( extended_module.present(other_entity_instance) ).to eq({
127
+ firstname: other_entity_instance.firstname,
128
+ lastname: other_entity_instance.lastname,
129
+ email: other_entity_instance.email,
130
+ is_admin: false
131
+ })
132
+ end
133
+
134
+
135
+ it "exposes `nil' values correctly" do
136
+ extended_module.presenter_for( other_entity_class ) do
137
+ expose :firstname
138
+ expose :lastname
139
+ expose :email
140
+ end
141
+
142
+ other_entity_instance.email = nil
143
+
144
+ expect( extended_module.present(other_entity_instance) ).to eq({
145
+ firstname: other_entity_instance.firstname,
146
+ lastname: other_entity_instance.lastname,
147
+ email: nil
148
+ })
149
+ end
150
+
151
+
94
152
  it "can be made conditional on an option being set" do
95
153
  extended_module.presenter_for( entity_class ) do
96
154
  expose :foo
@@ -119,10 +177,11 @@ RSpec.describe Presentability do
119
177
 
120
178
  expect {
121
179
  extended_module.present( entity_instance )
122
- }.to raise_error( NoMethodError, /can't expose :id -- no such attribute exists/i )
180
+ }.to raise_error( NoMethodError, /undefined method `id'/i )
123
181
  end
124
182
 
125
183
 
184
+
126
185
  describe "collection handling" do
127
186
 
128
187
  it "can present a collection" do
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: presentability
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Granger
@@ -33,7 +33,7 @@ cert_chain:
33
33
  P5YP5BAbNW+gvd3QHRiWTTuhgHrdDnGdXg93N2M5KHn1ug8BtPLQwlcFwEpKnlLn
34
34
  btEP+7EplFuoiMfd
35
35
  -----END CERTIFICATE-----
36
- date: 2022-12-06 00:00:00.000000000 Z
36
+ date: 2022-12-16 00:00:00.000000000 Z
37
37
  dependencies:
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: loggability
@@ -69,28 +69,28 @@ dependencies:
69
69
  requirements:
70
70
  - - "~>"
71
71
  - !ruby/object:Gem::Version
72
- version: '0.19'
72
+ version: '0.21'
73
73
  type: :development
74
74
  prerelease: false
75
75
  version_requirements: !ruby/object:Gem::Requirement
76
76
  requirements:
77
77
  - - "~>"
78
78
  - !ruby/object:Gem::Version
79
- version: '0.19'
79
+ version: '0.21'
80
80
  - !ruby/object:Gem::Dependency
81
- name: rdoc-generator-fivefish
81
+ name: rdoc-generator-sixfish
82
82
  requirement: !ruby/object:Gem::Requirement
83
83
  requirements:
84
84
  - - "~>"
85
85
  - !ruby/object:Gem::Version
86
- version: '0.4'
86
+ version: '0.2'
87
87
  type: :development
88
88
  prerelease: false
89
89
  version_requirements: !ruby/object:Gem::Requirement
90
90
  requirements:
91
91
  - - "~>"
92
92
  - !ruby/object:Gem::Version
93
- version: '0.4'
93
+ version: '0.2'
94
94
  description: Facade-based presenters with minimal assumptions. This library contains
95
95
  utilities for setting up presenters for data classes for things like web services,
96
96
  logging output, etc.
metadata.gz.sig CHANGED
Binary file