presentability 0.3.0 → 0.4.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
  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