presentability 0.1.0.pre.20220807214309

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9cb368623de9f8e87b526b7ec806fb7469230df1afc2092d1e83c5c00a134140
4
+ data.tar.gz: a2db6a19a38d9bea3113807df66eea6f5a4ba198647291f8c2269cf5c09e2182
5
+ SHA512:
6
+ metadata.gz: f4a042bd7a2abdb74182c429ab3889a2a9e50765f67676be07c2697a22156e364b48c3e182c9260515c96e99d73b585b4893a332720e63333187a66c976110cc
7
+ data.tar.gz: dd0e2b57e05dc7f1c568ada5e6d5c94dac338f176c233a0d4b1509d9c455bc6d07a1274cfda2b7fe48cb30b4619e9ef6c21f34dc8f76781718c2ed6d5b110ab5
data/History.md ADDED
@@ -0,0 +1,4 @@
1
+ ## v0.0.1 [YYYY-MM-DD] Michael Granger <ged@FaerieMUD.org>
2
+
3
+ Initial release.
4
+
data/LICENSE.txt ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2022, Michael Granger
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # Presentability
2
+
3
+ home
4
+ : https://hg.sr.ht/~ged/Presentability
5
+
6
+ code
7
+ : https://hg.sr.ht/~ged/Presentability
8
+
9
+ github
10
+ : https://github.com/ged/presentability
11
+
12
+ docs
13
+ : https://deveiate.org/code/presentability
14
+
15
+
16
+ ## Description
17
+
18
+ Facade-based presenters with minimal assumptions. This library contains
19
+ utilities for setting up presenters for data classes for things like web
20
+ services, logging output, etc.
21
+
22
+ It is intended to be dead-simple by default, returning a Hash containing
23
+ only the attributes you have intentionally exposed from the subject.
24
+
25
+ # lib/acme/widget.rb
26
+ class Acme::Widget
27
+ attr_accessor :sku,
28
+ :name,
29
+ :unit_price,
30
+ :internal_cost,
31
+ :inventory_count
32
+ end
33
+
34
+ # lib/acme/presenters.rb
35
+ module Acme::Presenters
36
+ extend Presentability
37
+
38
+ presenter_for Acme::Widget do
39
+ expose :sku
40
+ expose :name
41
+ expose :unit_price
42
+ end
43
+ end
44
+
45
+ # lib/acme/service.rb
46
+ class Acme::Service < Some::Webservice::Framework
47
+
48
+ on '/api/widgets/<sku>' do |sku|
49
+ widget = Acme::Widget.lookup( sku )
50
+ content_type 'application/json'
51
+ representation = Acme::Presenters.present( widget )
52
+ return representation.to_json
53
+ end
54
+
55
+ end
56
+
57
+ Note that Presentability doesn't do any encoding for you, or infer anything, or
58
+ require that you alter your data classes. It's just a collection of Facades for
59
+ your data objects that return a limited representation of their subjects.
60
+
61
+ More details can be found in the docs for the Presentability module, and in
62
+ Presentability::Presenter.
63
+
64
+
65
+ ## Prerequisites
66
+
67
+ * Ruby
68
+
69
+
70
+ ## Installation
71
+
72
+ $ gem install presentability
73
+
74
+
75
+ ## Contributing
76
+
77
+ You can check out the current development source with Mercurial via its
78
+ [project page](http://bitbucket.org/ged/presentability). Or if you prefer Git, via
79
+ [its Github mirror](https://github.com/ged/presentability).
80
+
81
+ After checking out the source and changing into the resulting directory, run:
82
+
83
+ $ gem install -Ng
84
+ $ rake setup
85
+
86
+ This will install dependencies, and do any other necessary setup for development.
87
+
88
+
89
+ ## Authors
90
+
91
+ - Michael Granger <ged@faeriemud.org>
92
+
93
+
94
+ ## License
95
+
96
+ Copyright (c) 2022, Michael Granger
97
+ All rights reserved.
98
+
99
+ Redistribution and use in source and binary forms, with or without
100
+ modification, are permitted provided that the following conditions are met:
101
+
102
+ * Redistributions of source code must retain the above copyright notice,
103
+ this list of conditions and the following disclaimer.
104
+
105
+ * Redistributions in binary form must reproduce the above copyright notice,
106
+ this list of conditions and the following disclaimer in the documentation
107
+ and/or other materials provided with the distribution.
108
+
109
+ * Neither the name of the author/s, nor the names of the project's
110
+ contributors may be used to endorse or promote products derived from this
111
+ software without specific prior written permission.
112
+
113
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
114
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
115
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
116
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
117
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
118
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
119
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
120
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
121
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
122
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
123
+
124
+
@@ -0,0 +1,84 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'loggability'
5
+
6
+ require 'presentability' unless defined?( Presentability )
7
+
8
+
9
+ class Presentability::Presenter
10
+ extend Loggability
11
+
12
+
13
+ # The exposure options used by every exposure unless overridden
14
+ DEFAULT_EXPOSURE_OPTIONS = {}.freeze
15
+
16
+
17
+ # Loggability API; use Presentability's logger
18
+ log_to :presentability
19
+
20
+
21
+ # This is an abstract class; disallow instantiation
22
+ private_class_method :new
23
+
24
+
25
+ ### Enable instantiation by subclasses.
26
+ def self::inherited( subclass )
27
+ super
28
+ subclass.public_class_method( :new )
29
+ subclass.exposures = {}
30
+ end
31
+
32
+
33
+ ##
34
+ # The Hash of exposures declared by this class
35
+ singleton_class.attr_accessor :exposures
36
+
37
+
38
+ ### Set up an exposure that will delegate to the attribute of the subject with
39
+ ### the given +name+.
40
+ def self::expose( name, options={} )
41
+ options = DEFAULT_EXPOSURE_OPTIONS.merge( options )
42
+
43
+ self.log.debug "Setting up exposure %p %p" % [ name, options ]
44
+ self.exposures[ name ] = options
45
+ end
46
+
47
+
48
+ ### Create a new Presenter for the given +subject+.
49
+ def initialize( subject )
50
+ @subject = subject
51
+ end
52
+
53
+
54
+ ######
55
+ public
56
+ ######
57
+
58
+ ##
59
+ # The subject of the presenter, the object that is delegated to when
60
+ # building the representation.
61
+ attr_reader :subject
62
+
63
+
64
+ ### Return a new instance of whatever object type will be used to represent the
65
+ ### subject.
66
+ def empty_representation
67
+ return {}
68
+ end
69
+
70
+
71
+ ### Apply the exposures to the subject and return the result.
72
+ def apply
73
+ result = self.empty_representation
74
+
75
+ self.class.exposures.each do |name, opts|
76
+ # :TODO: #public_send instead?
77
+ value = self.subject.send( name )
78
+ result[ name.to_sym ] = value
79
+ end
80
+
81
+ return result
82
+ end
83
+
84
+ end # class Presentability::Presenter
@@ -0,0 +1,60 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'loggability'
5
+
6
+
7
+ # Facade-based presenters with minimal assumptions.
8
+ module Presentability
9
+ extend Loggability
10
+
11
+
12
+ # Package version
13
+ VERSION = '0.0.1'
14
+
15
+
16
+ # Automatically load subordinate components
17
+ autoload :Presenter, 'presentability/presenter'
18
+
19
+
20
+ # Create a logger used by all Presentability modules
21
+ log_as :presentability
22
+
23
+
24
+ ### Extension hook -- decorate the including +mod+.
25
+ def self::extended( mod )
26
+ super
27
+ mod.singleton_class.attr_accessor :presenters
28
+ mod.presenters = {}
29
+ end
30
+
31
+
32
+
33
+ ### Set up a presentation for the given +entity_class+.
34
+ def presenter_for( entity_class, &block )
35
+ presenter_class = Class.new( Presentability::Presenter )
36
+ presenter_class.instance_eval( &block )
37
+
38
+ self.presenters[ entity_class ] = presenter_class
39
+ end
40
+
41
+
42
+ ### Return a representation of the +object+ by applying a declared presentation.
43
+ def present( object )
44
+ representation = self.present_by_class( object )
45
+
46
+ return representation
47
+ end
48
+
49
+
50
+ ### Return a representation of the +object+ by applying a presenter declared for its
51
+ ### class. Returns +nil+ if no such presenter exists.
52
+ def present_by_class( object )
53
+ presenter_class = self.presenters[ object.class ] or return nil
54
+ presenter = presenter_class.new( object )
55
+
56
+ return presenter.apply
57
+ end
58
+
59
+ end # module Presentability
60
+
@@ -0,0 +1,48 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ require 'rspec'
7
+ require 'presentability'
8
+
9
+
10
+ RSpec.describe Presentability do
11
+
12
+ let( :entity_class ) do
13
+ Class.new do
14
+ def initialize
15
+ @foo = 1
16
+ @bar = 'two'
17
+ @baz = :three
18
+ end
19
+
20
+ attr_accessor :foo, :bar, :baz
21
+ end
22
+ end
23
+
24
+ let( :entity_instance ) { entity_class.new }
25
+
26
+
27
+ describe "an extended module" do
28
+
29
+ subject do
30
+ mod = Module.new
31
+ mod.extend( described_class )
32
+ end
33
+
34
+
35
+ it "can define a presenter for an explicit class" do
36
+ subject.presenter_for( entity_class ) do
37
+ expose :foo
38
+ expose :bar
39
+ end
40
+
41
+ expect( subject.present(entity_instance) ).to eq({ foo: 1, bar: 'two' })
42
+ end
43
+
44
+
45
+ end
46
+
47
+ end
48
+
@@ -0,0 +1,30 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'simplecov' if ENV['COVERAGE']
5
+
6
+ require 'rspec'
7
+
8
+ require 'loggability/spechelpers'
9
+
10
+
11
+ ### Mock with RSpec
12
+ RSpec.configure do |config|
13
+ config.mock_with( :rspec ) do |mock|
14
+ mock.syntax = :expect
15
+ end
16
+
17
+ config.disable_monkey_patching!
18
+ config.example_status_persistence_file_path = "spec/.status"
19
+ config.filter_run :focus
20
+ config.filter_run_when_matching :focus
21
+ config.order = :random
22
+ config.profile_examples = 5
23
+ config.run_all_when_everything_filtered = true
24
+ config.shared_context_metadata_behavior = :apply_to_host_groups
25
+ # config.warnings = true
26
+
27
+ config.include( Loggability::SpecHelpers )
28
+ end
29
+
30
+
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: presentability
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.pre.20220807214309
5
+ platform: ruby
6
+ authors:
7
+ - Michael Granger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-08-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: loggability
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.18'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.18'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake-deveiate
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.19'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.19'
41
+ description: Facade-based presenters with minimal assumptions. This library contains
42
+ utilities for setting up presenters for data classes for things like web services,
43
+ logging output, etc.
44
+ email:
45
+ - ged@faeriemud.org
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - History.md
51
+ - LICENSE.txt
52
+ - README.md
53
+ - lib/presentability.rb
54
+ - lib/presentability/presenter.rb
55
+ - spec/presentability_spec.rb
56
+ - spec/spec_helper.rb
57
+ homepage: https://hg.sr.ht/~ged/Presentability
58
+ licenses:
59
+ - BSD-3-Clause
60
+ metadata:
61
+ bug_tracker_uri: https://todo.sr.ht/~ged/Presentability
62
+ changelog_uri: https://deveiate.org/code/presentability/History_md.html
63
+ documentation_uri: https://deveiate.org/code/presentability
64
+ homepage_uri: https://hg.sr.ht/~ged/Presentability
65
+ source_uri: https://hg.sr.ht/~ged/Presentability
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">"
78
+ - !ruby/object:Gem::Version
79
+ version: 1.3.1
80
+ requirements: []
81
+ rubygems_version: 3.3.7
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: Facade-based presenters with minimal assumptions.
85
+ test_files: []