presentability 0.3.0 → 0.4.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: ff4d9944824eaaa9ef6bc0d5e2b02879e83c481f2db9a39fe6c6ebc6f947dd7f
4
- data.tar.gz: 4ccd0e65bdaae2504bf6edad1df4aab25698d5290b740028c5f5dc7c78732302
3
+ metadata.gz: 67ea66c2c975ecb5064c9ddb9c0be1a203b0e9e9944dfc3f3821f07e360fc726
4
+ data.tar.gz: c13fdaccf960dc87d3feaed73e2a22a96ad805aed83cadbadeeee9cc60e80e49
5
5
  SHA512:
6
- metadata.gz: cae40ce72cd721000c47cff537ba2a2ac6635fc27205f79d81548471efda66b499c9aadd8eab97049a457dbd1c784e20ec5cd01805a57c511e1da808517c5ab8
7
- data.tar.gz: 73ccbe66aeeed78447ae7cb91a0bb9cdbe95325d834e6fcfc6baaa4c96103cfb03efa4ef55f3718098ad021f211c17d5365f2e528b0dc5e846570ff6bec3407d
6
+ metadata.gz: 550a710c7ae589dfc6ebb1ed801508c8e2d347dbd37e1cdd19e3f3699b5b203ad38b7f2dc6a917e71d3e3dd3711e4eefe8c01594a1f4d92f10b120c4fe1e0a82
7
+ data.tar.gz: 07d9674d3ad188b6b19923153accddf6175bf61d238d79867b7237a34a10595e066e10f4d37cc702bbcca8b7dcf65fd7df75ad0eb2fa0c4557716be3a370090b
checksums.yaml.gz.sig CHANGED
@@ -1,2 +1,4 @@
1
- ��~�>����;O* :p����ݔ��ٰK ^[���>Y*ΫY9��cc���qe+�!f��~;�Ib�*�,��,h���z��0j��p���d�U�H���+`��čZf����������YN��&8Y��k�a*;!`��I9(T�/�+B�*�qj��Q���Ḯ�����X9��ό�Y&l@����H^��4D�~�&��?H����C)�v����1G+_sA{�7X�|͓��
2
- �lO+�L.�2
1
+ p�kV��V��HNl*�zK3]<�[�>"��oNP��3O�-ф��ں<�W��ȁî��~������O���������{��a�Z�� c���Jh�a)^\����/�JDMNf׹9�� ��
2
+ /�;!��C
3
+ ���&9u���NI� X��1l7�Po �p�|�T��VI:��t} ���E�
4
+ ��| ��I�_gfM��*B7�O�Dw���,��6�v���B?��Ro$��3&���
data/History.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # Release History for presentability
2
2
 
3
3
  ---
4
+ ## v0.4.0 [2023-02-02] Michael Granger <ged@faeriemud.org>
5
+
6
+ Improvements:
7
+
8
+ - Add presentation aliases.
9
+
10
+
4
11
  ## v0.3.0 [2022-12-16] Michael Granger <ged@faeriemud.org>
5
12
 
6
13
  Improvements:
data/Presentability.md ADDED
@@ -0,0 +1,105 @@
1
+
2
+ Facade-based presenter toolkit with minimal assumptions.
3
+
4
+ ## Basic Usage
5
+
6
+ Basic usage of Presentability requires two steps: declaring presenters and
7
+ then using them.
8
+
9
+ ### Declaring Presenters
10
+
11
+ Presenters are just regular Ruby classes with some convenience methods for
12
+ declaring exposures, but in a lot of cases you'll want to declare them all in
13
+ one place. Presentability offers a mixin that implements a simple DSL for
14
+ declaring presenters and their associations to entity classes, intended to be
15
+ used in a container module:
16
+
17
+ require 'presentability'
18
+
19
+ module Acme::Presenters
20
+ extend Presentability
21
+
22
+ presenter_for( Acme::Widget ) do
23
+ expose :sku
24
+ expose :name
25
+ expose :unit_price
26
+ end
27
+
28
+ end
29
+
30
+ The block of `presenter_for` is evaluated in the context of a new Presenter
31
+ class, so refer to that documentation for what's possible there.
32
+
33
+ Sometimes you can't (or don't want to) have to load the entity class to
34
+ declare a presenter for it, so you can also declare it using the class's name:
35
+
36
+ presenter_for( 'Acme::Widget' ) do
37
+ expose :sku
38
+ expose :name
39
+ expose :unit_price
40
+ end
41
+
42
+
43
+ ### Using Presenters
44
+
45
+ You use presenters by instantiating them with the object they are a facade for
46
+ (the "subject"), and then applying it:
47
+
48
+ acme_widget = Acme::Widget.new(
49
+ sku: "FF-2237H455",
50
+ name: "Throbbing Frobnulator",
51
+ unit_price: 299,
52
+ inventory_count: 301,
53
+ wholesale_cost: 39
54
+ )
55
+ presentation = Acme::Presenters.present( acme_widget )
56
+ # => { :sku => "FF-2237H455", :name => "Throbbing Frobnulator", :unit_price => 299 }
57
+
58
+ If you want to present a collection of objects as a collection, you can apply presenters to the collection instead:
59
+
60
+ widgets_in_stock = Acme::Widget.where { inventory_count > 0 }
61
+ collection_presentation = Acme::Presenters.present_collection( widgets_in_stock )
62
+ # => [ {:sku => "FF-2237H455", [...]}, {:sku => "FF-2237H460", [...]}, [...] ]
63
+
64
+ The collection can be anything that is `Enumerable`.
65
+
66
+
67
+ ### Presentation Options
68
+
69
+ Sometimes you want a bit more flexibility in what you present, allowing a single uniform presenter to be used in multiple use cases. To facilitate this, you can pass an options keyword hash to `#present`:
70
+
71
+ presenter_for( 'Acme::Widget' ) do
72
+ expose :sku
73
+ expose :name
74
+ expose :unit_price
75
+
76
+ # Only expose the wholesale cost if presented via an internal API
77
+ expose :wholesale_cost, if: :internal_api
78
+ end
79
+
80
+ acme_widget = Acme::Widget.new(
81
+ sku: "FF-2237H455",
82
+ name: "Throbbing Frobnulator",
83
+ unit_price: 299,
84
+ inventory_count: 301,
85
+ wholesale_cost: 39
86
+ )
87
+
88
+ # External API remains unchanged:
89
+ presentation = Acme::Presenters.present( acme_widget )
90
+ # => { :sku => "FF-2237H455", :name => "Throbbing Frobnulator", :unit_price => 299 }
91
+
92
+ # But when run from an internal service:
93
+ internal_presentation = Acme::Presenters.present( acme_widget, internal_api: true )
94
+ # => { :sku => "FF-2237H455", :name => "Throbbing Frobnulator", :unit_price => 299,
95
+ # :wholesale_cost => 39 }
96
+
97
+ There are some options that are set for you:
98
+
99
+ <dl>
100
+ <td><code>:in_collection</code></td>
101
+ <dd>Set if the current object is being presented as part of a collection.</dd>
102
+ </dl>
103
+
104
+
105
+
data/Presenter.md ADDED
@@ -0,0 +1,109 @@
1
+
2
+ A presenter (facade) base class.
3
+
4
+
5
+ ### Declaring Presenters
6
+
7
+ When you declare a presenter in a Presentability collection, the result is a
8
+ subclass of Presentability::Presenter. The main way of defining a Presenter's
9
+ functionality is via the ::expose method, which marks an attribute of the underlying
10
+ entity object (the "subject") for exposure.
11
+
12
+ class MyPresenter < Presentability::Presenter
13
+ expose :name
14
+ end
15
+
16
+ # Assuming `entity_object' has a "name" attribute...
17
+ presenter = MyPresenter.new( entity_object )
18
+ presenter.apply
19
+ # => { :name => "entity name" }
20
+
21
+
22
+ ### Presenter Collections
23
+
24
+ Setting up classes manually like this is one option, but Presentability also lets you
25
+ set them up as a collection, which is what further examples will assume for brevity:
26
+
27
+ module MyPresenters
28
+ extend Presentability
29
+
30
+ presenter_for( EntityObject ) do
31
+ expose :name
32
+ end
33
+
34
+ end
35
+
36
+
37
+ ### Complex Exposures
38
+
39
+ Sometimes you want to do more than just use the presented entity's values as-is. There are a number of ways to do this.
40
+
41
+ The first of these is to provide a block when exposing an attribute. The subject of the presenter is available to the block via the `subject` method:
42
+
43
+ require 'time'
44
+
45
+ presenter_for( LogEvent ) do
46
+ # Turn Time objects into RFC2822-formatted time strings
47
+ expose :timestamp do
48
+ self.subject.timestamp.rfc2822
49
+ end
50
+
51
+ end
52
+
53
+ You can also declare the exposure using a regular method with the same name:
54
+
55
+ require 'time'
56
+
57
+ presenter_for( LogEvent ) do
58
+ # Turn Time objects into RFC2822-formatted time strings
59
+ expose :timestamp
60
+
61
+ def timestamp
62
+ return self.subject.timestamp.rfc2822
63
+ end
64
+
65
+ end
66
+
67
+ This can be used to add presence checks:
68
+
69
+ require 'time'
70
+
71
+ presenter_for( LogEvent ) do
72
+ # Require that presented entities have an `id` attribute
73
+ expose :id do
74
+ id = self.subject.id or raise "no `id' for %p" % [ self.subject ]
75
+ raise "`id' for %p is blank!" % [ self.subject ] if id.blank?
76
+
77
+ return id
78
+ end
79
+ end
80
+
81
+ or conditional exposures:
82
+
83
+ presenter_for( Acme::Product ) do
84
+
85
+ # Truncate the long description if presented as part of a collection
86
+ expose :detailed_description do
87
+ desc = self.subject.detailed_description
88
+ if self.options[:in_collection]
89
+ return desc[0..15] + '...'
90
+ else
91
+ return desc
92
+ end
93
+ end
94
+
95
+ end
96
+
97
+
98
+ ### Exposure Aliases
99
+
100
+ If you want to expose a field but use a different name in the resulting data structure, you can use the `:as` option in the exposure declaration:
101
+
102
+ presenter_for( LogEvent ) do
103
+ expose :timestamp, as: :created_at
104
+ end
105
+
106
+ presenter = MyPresenter.new( log_event )
107
+ presenter.apply
108
+ # => { :created_at => '2023-02-01 12:34:02.155365 -0800' }
109
+
@@ -1,43 +1,10 @@
1
1
  # -*- ruby -*-
2
- # frozen_string_literal: true
3
2
 
4
3
  require 'loggability'
5
4
 
6
5
  require 'presentability' unless defined?( Presentability )
7
6
 
8
- #
9
- # A presenter (facade) base class.
10
- #
11
- # When you declare a presenter in a Presentability collection, the result is a
12
- # subclass of Presentability::Presenter. The main way of defining a Presenter's
13
- # functionality is via the ::expose method, which marks an attribute of the underlying
14
- # entity object (the "subject") for exposure.
15
- #
16
- # ```ruby
17
- # class MyPresenter < Presentability::Presenter
18
- # expose :name
19
- # end
20
- #
21
- # # Assuming `entity_object' has a "name" attribute...
22
- # presenter = MyPresenter.new( entity_object )
23
- # presenter.apply
24
- # # => { :name => "entity name" }
25
- # ```
26
- #
27
- # Setting up classes like this manually is one option, but Presentability also lets you
28
- # set them up as a collection, which is what further examples will assume for brevity:
29
- #
30
- # ```ruby
31
- # module MyPresenters
32
- # extend Presentability
33
- #
34
- # presenter_for( EntityObject ) do
35
- # expose :name
36
- # end
37
- #
38
- # end
39
- # ```
40
- #
7
+ # :include: Presenter.md
41
8
  class Presentability::Presenter
42
9
  extend Loggability
43
10
 
@@ -63,6 +30,7 @@ class Presentability::Presenter
63
30
 
64
31
 
65
32
  ##
33
+ # :singleton-method: exposures
66
34
  # The Hash of exposures declared by this class
67
35
  singleton_class.attr_accessor :exposures
68
36
 
@@ -80,6 +48,10 @@ class Presentability::Presenter
80
48
  define_method( name, &method_body )
81
49
  end
82
50
 
51
+ if (exposure_alias = options[:as]) && self.exposures.key?( exposure_alias )
52
+ raise ScriptError, "alias %p collides with another exposure" % [ exposure_alias ]
53
+ end
54
+
83
55
  self.log.debug "Setting up exposure %p, options = %p" % [ name, options ]
84
56
  self.exposures[ name ] = options
85
57
  end
@@ -141,7 +113,8 @@ class Presentability::Presenter
141
113
  self.class.exposures.each do |name, exposure_options|
142
114
  next if self.skip_exposure?( name )
143
115
  value = self.method( name ).call
144
- result[ name.to_sym ] = value
116
+ key = exposure_options.key?( :as ) ? exposure_options[:as] : name
117
+ result[ key.to_sym ] = value
145
118
  end
146
119
 
147
120
  return result
@@ -1,78 +1,15 @@
1
1
  # -*- ruby -*-
2
- # frozen_string_literal: true
3
2
 
4
3
  require 'loggability'
5
4
 
6
5
 
7
- # Facade-based presenter toolkit with minimal assumptions.
8
- #
9
- # ## Basic Usage
10
- #
11
- # Basic usage of Presentability requires two steps: declaring presenters and
12
- # then using them.
13
- #
14
- # ### Declaring Presenters
15
- #
16
- # Presenters are just regular Ruby classes with some convenience methods for
17
- # declaring exposures, but in a lot of cases you'll want to declare them all in
18
- # one place. Presentability offers a mixin that implements a simple DSL for
19
- # declaring presenters and their associations to entity classes, intended to be
20
- # used in a container module:
21
- #
22
- # ```ruby
23
- # require 'presentability'
24
- #
25
- # module Acme::Presenters
26
- # extend Presentability
27
- #
28
- # presenter_for( Acme::Widget ) do
29
- # expose :sku
30
- # expose :name
31
- # expose :unit_price
32
- # end
33
- #
34
- # end
35
- # ```
36
- #
37
- # The block of `presenter_for` is evaluated in the context of a new Presenter
38
- # class, so refer to that documentation for what's possible there.
39
- #
40
- # Sometimes you can't (or don't want to) have to load the entity class to
41
- # declare a presenter for it, so you can also declare it using the class's name:
42
- #
43
- # ```ruby
44
- # presenter_for( 'Acme::Widget' ) do
45
- # expose :sku
46
- # expose :name
47
- # expose :unit_price
48
- # end
49
- # ```
50
- #
51
- # ### Using Presenters
52
- #
53
- # You use presenters by instantiating them with the object they are a facade for
54
- # (the "subject"), and then applying it:
55
- #
56
- # ```ruby
57
- # acme_widget = Acme::Widget.new(
58
- # sku: "FF-2237H455",
59
- # name: "Throbbing Frobnulator",
60
- # unit_price: 299,
61
- # inventory_count: 301,
62
- # wholesale_cost: 39
63
- # )
64
- # presenter = Acme::Presenters.present( acme_widget )
65
- # presenter.apply
66
- # # => { :sku => "FF-2237H455", :name => "Throbbing Frobnulator", :unit_price => 299 }
67
- # ```
68
- #
69
- #
6
+ # :include: Presentability.md
70
7
  module Presentability
71
8
  extend Loggability
72
9
 
73
10
 
74
11
  # Package version
75
- VERSION = '0.3.0'
12
+ VERSION = '0.4.0'
76
13
 
77
14
 
78
15
  # Automatically load subordinate components
@@ -114,6 +51,7 @@ module Presentability
114
51
  ### Return an Array of all representations of the members of the
115
52
  ### +collection+ by applying a declared presentation.
116
53
  def present_collection( collection, **options )
54
+ options = options.merge( in_collection: true )
117
55
  return collection.map {|object| self.present(object, **options) }
118
56
  end
119
57
 
@@ -1,5 +1,4 @@
1
1
  # -*- ruby -*-
2
- # frozen_string_literal: true
3
2
 
4
3
  require_relative '../spec_helper'
5
4
 
@@ -21,7 +20,7 @@ RSpec.describe( Presentability::Presenter ) do
21
20
  end
22
21
 
23
22
 
24
- describe "a concrete subclass" do
23
+ describe "concrete subclass" do
25
24
 
26
25
  let( :subclass ) { Class.new(described_class) }
27
26
 
@@ -1,5 +1,4 @@
1
1
  # -*- ruby -*-
2
- # frozen_string_literal: true
3
2
 
4
3
  require_relative 'spec_helper'
5
4
 
@@ -55,7 +54,7 @@ RSpec.describe Presentability do
55
54
  end
56
55
 
57
56
 
58
- describe "an extended module" do
57
+ describe "when used to extend a module" do
59
58
 
60
59
  let( :extended_module ) do
61
60
  mod = Module.new
@@ -181,10 +180,38 @@ RSpec.describe Presentability do
181
180
  end
182
181
 
183
182
 
183
+ it "can alias a field to a different name" do
184
+ extended_module.presenter_for( entity_class ) do
185
+ expose :foo, as: :bar
186
+ end
187
+
188
+ expect( extended_module.present(entity_instance) ).to eq({ bar: 1 })
189
+ end
190
+
191
+
192
+ it "doesn't error when aliasing a field to itself" do
193
+ extended_module.presenter_for( entity_class ) do
194
+ expose :foo, as: :foo
195
+ expose :bar, as: :floom
196
+ end
197
+
198
+ expect( extended_module.present(entity_instance) ).to eq({ foo: 1, floom: 'two' })
199
+ end
200
+
201
+
202
+ it "raises if an alias clobbers another field" do
203
+ expect {
204
+ extended_module.presenter_for( entity_class ) do
205
+ expose :foo
206
+ expose :bar, as: :foo
207
+ end
208
+ }.to raise_error( ScriptError, /alias :foo collides with another exposure/i )
209
+ end
210
+
184
211
 
185
- describe "collection handling" do
212
+ describe "and used to present a collection" do
186
213
 
187
- it "can present a collection" do
214
+ it "handles a homogeneous collection" do
188
215
  extended_module.presenter_for( entity_class ) do
189
216
  expose :foo
190
217
  expose :bar
@@ -203,7 +230,7 @@ RSpec.describe Presentability do
203
230
  end
204
231
 
205
232
 
206
- it "can present a mixed collection" do
233
+ it "handles a hetergeneous collection" do
207
234
  extended_module.presenter_for( entity_class ) do
208
235
  expose :foo
209
236
  expose :bar
@@ -260,6 +287,24 @@ RSpec.describe Presentability do
260
287
  end
261
288
  end
262
289
 
290
+
291
+ it "sets the :in_collection option to allow for eliding attributes" do
292
+ extended_module.presenter_for( entity_class ) do
293
+ expose :foo
294
+ expose :bar, unless: :in_collection
295
+ expose :baz
296
+ end
297
+
298
+ results = extended_module.present_collection( [entity_instance] )
299
+
300
+ expect( results.first ).to include( :foo, :baz )
301
+ expect( results.first ).not_to include( :bar )
302
+
303
+ result = extended_module.present( entity_instance )
304
+
305
+ expect( result ).to include( :foo, :bar, :baz )
306
+ end
307
+
263
308
  end
264
309
 
265
310
  end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,13 @@
1
1
  # -*- ruby -*-
2
- # frozen_string_literal: true
3
2
 
4
- require 'simplecov' if ENV['COVERAGE']
3
+ if ENV['COVERAGE']
4
+ require 'simplecov'
5
+ SimpleCov.start do
6
+ add_filter 'spec/'
7
+ enable_coverage :branch
8
+ primary_coverage :branch
9
+ end
10
+ end
5
11
 
6
12
  require 'rspec'
7
13
  require 'i18n'
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.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Granger
@@ -10,9 +10,9 @@ bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIID+DCCAmCgAwIBAgIBBDANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBdnZWQv
14
- REM9RmFlcmllTVVEL0RDPW9yZzAeFw0yMjAxMDcyMzU4MTRaFw0yMzAxMDcyMzU4
15
- MTRaMCIxIDAeBgNVBAMMF2dlZC9EQz1GYWVyaWVNVUQvREM9b3JnMIIBojANBgkq
13
+ MIID+DCCAmCgAwIBAgIBBTANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBdnZWQv
14
+ REM9RmFlcmllTVVEL0RDPW9yZzAeFw0yMzAxMTYxNzE2MDlaFw0yNDAxMTYxNzE2
15
+ MDlaMCIxIDAeBgNVBAMMF2dlZC9EQz1GYWVyaWVNVUQvREM9b3JnMIIBojANBgkq
16
16
  hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAvyVhkRzvlEs0fe7145BYLfN6njX9ih5H
17
17
  L60U0p0euIurpv84op9CNKF9tx+1WKwyQvQP7qFGuZxkSUuWcP/sFhDXL1lWUuIl
18
18
  M4uHbGCRmOshDrF4dgnBeOvkHr1fIhPlJm5FO+Vew8tSQmlDsosxLUx+VB7DrVFO
@@ -23,17 +23,17 @@ cert_chain:
23
23
  ozilJg4aar2okb/RA6VS87o+d7g6LpDDMMQjH4G9OPnJENLdhu8KnPw/ivSVvQw7
24
24
  N2I4L/ZOIe2DIVuYH7aLHfjZDQv/mNgpAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYD
25
25
  VR0PBAQDAgSwMB0GA1UdDgQWBBRyjf55EbrHagiRLqt5YAd3yb8k4DANBgkqhkiG
26
- 9w0BAQsFAAOCAYEASrm1AbEoxACZ9WXJH3R5axV3U0CA4xaETlL2YT+2nOfVBMQ9
27
- 0ZlkPx6j4ghKJgAIi1TMfDM2JyPJsppQh8tiNccDjWc62UZRY/dq26cMqf/lcI+a
28
- 6YBuEYvzZfearwVs8tHnXtwYV3WSCoCOQaB+nq2lA1O+nkKNl41WOsVbNama5jx3
29
- 8cQtVSEEmZy6jIDJ8c5TmBJ7BQUDEUEWA/A3V42Xyctoj7DvUXWE0lP+X6ypAVSr
30
- lFh3TS64D7NTvxkmg7natUoCvobl6kGl4yMaqE4YRTlfuzhpf91TSOntClqrAOsS
31
- K1s56WndQj3IoBocdY9mQhDZLtLHofSkymoP8btBlj5SsN24TiF0VMSZlctSCYZg
32
- GKyHim/MMlIfGOWsgfioq5jzwmql7W4CDubbb8Lkg70v+hN2E/MnNVAcNE3gyaGc
33
- P5YP5BAbNW+gvd3QHRiWTTuhgHrdDnGdXg93N2M5KHn1ug8BtPLQwlcFwEpKnlLn
34
- btEP+7EplFuoiMfd
26
+ 9w0BAQsFAAOCAYEARYCeUVBWARNKqF0cvNnLJvFf4hdW2+Rtc7NfC5jQvX9a1oom
27
+ sfVvS96eER/9cbrphu+vc59EELw4zT+RY3/IesnoE7CaX6zIOFmSmG7K61OHsSLR
28
+ KqMygcWwyuPXT2JG7JsGHuxbzgaRWe29HbSjBbLYxiMH8Zxh4tKutxzKF7jb0Ggq
29
+ KAf9MH5LwG8IHVIfV5drT14PvgR3tcvmrn1timPyJl+eZ3LNnm9ofOCweuZCq1cy
30
+ 4Q8LV3vP2Cofy9q+az3DHdaUGlmMiZZZqKixDr1KSS9nvh0ZrKMOUL1sWj/IaxrQ
31
+ RV3y6td14q49t+xnbj00hPlbW7uE2nLJLt2NAoXiE1Nonndz1seB2c6HL79W9fps
32
+ E/O12pQjCp/aPUZMt8/8tKW31RIy/KP8XO6OTJNWA8A/oNEI0g5p/LmmEtJKWYr1
33
+ WmEdESlpWhzFECctefIF2lsN9vaOuof57RM77t2otrtcscDtNarIqjZsIyqtDvtL
34
+ DttITiit0Vwz7bY0
35
35
  -----END CERTIFICATE-----
36
- date: 2022-12-16 00:00:00.000000000 Z
36
+ date: 2023-02-02 00:00:00.000000000 Z
37
37
  dependencies:
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: loggability
@@ -102,6 +102,8 @@ extra_rdoc_files: []
102
102
  files:
103
103
  - History.md
104
104
  - LICENSE.txt
105
+ - Presentability.md
106
+ - Presenter.md
105
107
  - README.md
106
108
  - lib/presentability.rb
107
109
  - lib/presentability/presenter.rb
@@ -132,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
134
  - !ruby/object:Gem::Version
133
135
  version: '0'
134
136
  requirements: []
135
- rubygems_version: 3.3.7
137
+ rubygems_version: 3.4.6
136
138
  signing_key:
137
139
  specification_version: 4
138
140
  summary: Facade-based presenters with minimal assumptions.
metadata.gz.sig CHANGED
Binary file