gift_wrap 0.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 +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +56 -0
- data/LICENSE.md +27 -0
- data/README.md +1 -0
- data/Rakefile +7 -0
- data/lib/gift_wrap.rb +16 -0
- data/lib/gift_wrap/active_record_presenter.rb +54 -0
- data/lib/gift_wrap/configuration.rb +15 -0
- data/lib/gift_wrap/presenter.rb +126 -0
- data/lib/gift_wrap/version.rb +3 -0
- data/test/database/schema.rb +14 -0
- data/test/domain/legend.rb +18 -0
- data/test/domain/map.rb +26 -0
- data/test/domain/user.rb +7 -0
- data/test/fixtures/user_records.rb +37 -0
- data/test/test_helper.rb +70 -0
- data/test/unit/active_record_presenter_test.rb +115 -0
- data/test/unit/configuration_test.rb +43 -0
- data/test/unit/presenter_test.rb +259 -0
- metadata +194 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 37ded86a1243c84591148c1c278126e00eca4c05
|
4
|
+
data.tar.gz: cc8f73fc149fdc246b96b43fa597d250562d429e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a1b13e46b2b4c1eae2aa13e6b5d3c386ae4c2efd211ca6b015c3c7e86edebd9e96ab8ba069e0dd51c9edf594ae7c6a7b5b9547ef0b11662b439af1300e65df46
|
7
|
+
data.tar.gz: 782ab93cb6d43ffdd15faa770ee183a06f94d56a05a0442c2df21adfce77dca24256ef8d4fbe8152a197f138ca40d9c8e3b27719618b3958cbf244bc318b2469
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
gift_wrap (0.2.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activemodel (4.2.6)
|
10
|
+
activesupport (= 4.2.6)
|
11
|
+
builder (~> 3.1)
|
12
|
+
activerecord (4.2.6)
|
13
|
+
activemodel (= 4.2.6)
|
14
|
+
activesupport (= 4.2.6)
|
15
|
+
arel (~> 6.0)
|
16
|
+
activesupport (4.2.6)
|
17
|
+
i18n (~> 0.7)
|
18
|
+
json (~> 1.7, >= 1.7.7)
|
19
|
+
minitest (~> 5.1)
|
20
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
21
|
+
tzinfo (~> 1.1)
|
22
|
+
ansi (1.5.0)
|
23
|
+
arel (6.0.3)
|
24
|
+
builder (3.2.2)
|
25
|
+
i18n (0.7.0)
|
26
|
+
json (1.8.3)
|
27
|
+
minitest (5.9.0)
|
28
|
+
minitest-reporters (1.1.9)
|
29
|
+
ansi
|
30
|
+
builder
|
31
|
+
minitest (>= 5.0)
|
32
|
+
ruby-progressbar
|
33
|
+
rake (10.5.0)
|
34
|
+
ruby-progressbar (1.8.1)
|
35
|
+
sqlite3 (1.3.11)
|
36
|
+
thread_safe (0.3.5)
|
37
|
+
turn-again-reporter (1.1.0)
|
38
|
+
minitest-reporters (~> 1.0, >= 1.0.8)
|
39
|
+
tzinfo (1.2.2)
|
40
|
+
thread_safe (~> 0.1)
|
41
|
+
|
42
|
+
PLATFORMS
|
43
|
+
ruby
|
44
|
+
|
45
|
+
DEPENDENCIES
|
46
|
+
activemodel (~> 4.0)
|
47
|
+
activerecord (~> 4.0, >= 4.0.0)
|
48
|
+
bundler (~> 1.7)
|
49
|
+
gift_wrap!
|
50
|
+
minitest-reporters (~> 1.1)
|
51
|
+
rake (~> 10.0)
|
52
|
+
sqlite3 (~> 1.3, >= 1.3.0)
|
53
|
+
turn-again-reporter (~> 1.1, >= 1.1.0)
|
54
|
+
|
55
|
+
BUNDLED WITH
|
56
|
+
1.12.5
|
data/LICENSE.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Copyright (c) 2016, Paul Kwiatkowski
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
* 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
|
+
* Neither the name of adalog nor the names of its
|
15
|
+
contributors may be used to endorse or promote products derived from
|
16
|
+
this software without specific prior written permission.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
22
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
23
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
24
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
25
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
26
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# GiftWrap
|
data/Rakefile
ADDED
data/lib/gift_wrap.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module GiftWrap
|
2
|
+
|
3
|
+
def self.config
|
4
|
+
@config ||= GiftWrap::Configuration.new
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
def self.configure
|
9
|
+
yield(config)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
Dir[File.join(File.dirname(__FILE__), "gift_wrap", "*.rb")].each do |rb_file|
|
15
|
+
require rb_file
|
16
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module GiftWrap
|
2
|
+
module ActiveRecordPresenter
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:include, ::GiftWrap::Presenter)
|
6
|
+
base.extend(::GiftWrap::ActiveRecordPresenter::ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
##
|
13
|
+
# Sets delegate methods via ::unwrap_for en masse for all columns.
|
14
|
+
# The :attribute keyword argument can specify which columns are attributes
|
15
|
+
# in one of three ways from different values:
|
16
|
+
# - true: all columns will be considered attributes
|
17
|
+
# - false: no columns will be considered attributes
|
18
|
+
# - A hash with the key :only, whose value specifies which columns to consider as
|
19
|
+
# attributes, either singular or as an array of column names.
|
20
|
+
# - A hash with the key :except, whose value specifies which columns to consider as
|
21
|
+
# attributes, either singular or as an array of column names.
|
22
|
+
def unwrap_columns_for(active_record_model, attribute: true, **options)
|
23
|
+
columns = active_record_model.columns.map { |col| col.name.to_sym }
|
24
|
+
if true == attribute || false == attribute
|
25
|
+
unwrap_for(*columns, attribute: attribute, **options)
|
26
|
+
elsif Hash === attribute
|
27
|
+
as_attributes, not_attributes = partition_columns_for_attributes(columns, attribute)
|
28
|
+
unwrap_for(*as_attributes, attribute: true, **options)
|
29
|
+
unwrap_for(*not_attributes, attribute: false, **options)
|
30
|
+
else
|
31
|
+
unwrap_for(*columns, attribute: attribute, **options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def partition_columns_for_attributes(columns, attribute_options)
|
38
|
+
partitioned =
|
39
|
+
if attribute_options.key?(:only)
|
40
|
+
accepted_columns = [attribute_options.fetch(:only)].flatten
|
41
|
+
columns.partition { |col| accepted_columns.include?(col) }
|
42
|
+
elsif attribute_options.key?(:except)
|
43
|
+
rejected_columns = [attribute_options.fetch(:except)].flatten
|
44
|
+
columns.partition { |col| !rejected_columns.include?(col) }
|
45
|
+
else
|
46
|
+
[columns, []]
|
47
|
+
end
|
48
|
+
return *partitioned
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module GiftWrap
|
2
|
+
module Presenter
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
if GiftWrap.config.use_serializers? && defined? ActiveModel::Serializers::JSON
|
7
|
+
base.send(:include, ActiveModel::Serializers::JSON)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# Current options:
|
13
|
+
# - associations: a hash mapping association names to the presenter class
|
14
|
+
# to use when wrapping the association. Used to override the :with setting of
|
15
|
+
# a call to ::wrap_association at an instance level.
|
16
|
+
def initialize(wrapped_object, **options)
|
17
|
+
@wrapped_object = wrapped_object
|
18
|
+
@wrapped_association_presenters = options.fetch(:associations, {})
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Used in methods defined by ::wrap_association to determine the presenter class that
|
23
|
+
# is used for a particular association name. First checks any instance-specific options
|
24
|
+
# for the association name, and falls back to those defined by the :with option passed
|
25
|
+
# to any ::wrap_association call for said association_name.
|
26
|
+
def wrapped_association_presenter(association_name)
|
27
|
+
if @wrapped_association_presenters.none?
|
28
|
+
self.class.wrapped_association_defaults.fetch(association_name) do |name|
|
29
|
+
raise NoMethodError.new("No association registered as '#{name}'.")
|
30
|
+
end
|
31
|
+
else
|
32
|
+
@wrapped_association_presenters.fetch(
|
33
|
+
association_name,
|
34
|
+
self.class.wrapped_association_defaults.fetch(association_name) do |name|
|
35
|
+
raise NoMethodError.new("No association registered as '#{name}'.")
|
36
|
+
end)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# For use by ActiveModel::Serializers::JSON in building a default set of values
|
42
|
+
# when calling #as_json or #to_json
|
43
|
+
def attributes
|
44
|
+
self.class.attributes.each.with_object({}) do |msg, attr_hash|
|
45
|
+
attr_hash[msg.to_s] = self.send(msg)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
module ClassMethods
|
51
|
+
|
52
|
+
##
|
53
|
+
# Contains the of messages (which are used as hash keys) to send to self and collect
|
54
|
+
# when building an attributes hash.
|
55
|
+
def attributes
|
56
|
+
@attributes ||= Set.new
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Contains the list of methods which will be delegated to the wrapped object rather than
|
61
|
+
# defined on presenter class itself.
|
62
|
+
def unwrapped_methods
|
63
|
+
@unwrapped_methods ||= Set.new
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Contains the default settings for building any associations. These may be overridden
|
68
|
+
# on a per-intance basis.
|
69
|
+
def wrapped_association_defaults
|
70
|
+
@wrapped_association_defaults ||= {}
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Defines a private method name by which the wrapped object may be referenced internally.
|
75
|
+
def wrapped_as(reference)
|
76
|
+
define_method(reference) do
|
77
|
+
@wrapped_object
|
78
|
+
end
|
79
|
+
send(:private, reference)
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Declares one or more messages (method names) to be attributes.
|
84
|
+
def attribute(*names)
|
85
|
+
names.flatten.each do |name|
|
86
|
+
attributes << name
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# Declares that one or more received messages (method calls) should be delegated directly
|
92
|
+
# to the wrapped object, and which may be optionally declared as attributes.
|
93
|
+
#
|
94
|
+
def unwrap_for(*names, attribute: false, **options)
|
95
|
+
names = names.flatten
|
96
|
+
names.each do |name|
|
97
|
+
unwrapped_methods << name
|
98
|
+
attributes << name if attribute
|
99
|
+
end
|
100
|
+
delegate(*names, to: :@wrapped_object)
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Declares that the result of a delegated method call should be wrapped in another
|
105
|
+
# presenter, as defined by the :with keyword argument.
|
106
|
+
# This results in a method by the name of the first parameter by default, but may be
|
107
|
+
# customized with the :as keyword argument.
|
108
|
+
# Associations whose method produces an enumerable (ideally an Array) will have each
|
109
|
+
# item wrapped in the presenter and collected in an Array which is then returned.
|
110
|
+
def wrap_association(association, with: , as: association, **options)
|
111
|
+
wrapped_association_defaults[as] = with
|
112
|
+
define_method(as) do
|
113
|
+
presenter_class = wrapped_association_presenter(as)
|
114
|
+
associated = @wrapped_object.send(association)
|
115
|
+
if associated.respond_to?(:each)
|
116
|
+
associated.map { |assoc| presenter_class.new(assoc, **options) }
|
117
|
+
else
|
118
|
+
presenter_class.new(associated, **options)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
self.verbose = false
|
3
|
+
|
4
|
+
create_table :users, :force => true do |t|
|
5
|
+
t.string :email
|
6
|
+
t.string :first_name
|
7
|
+
t.string :last_name
|
8
|
+
t.string :encrypted_password
|
9
|
+
t.integer :sign_in_count
|
10
|
+
|
11
|
+
t.timestamps null: false
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
##
|
2
|
+
# An object to associate with a map, for testing associations & wrapping thereof.
|
3
|
+
class Legend
|
4
|
+
|
5
|
+
def initialize(colored_regions, colored_lines)
|
6
|
+
@colored_regions = colored_regions
|
7
|
+
@colored_lines = colored_lines
|
8
|
+
end
|
9
|
+
|
10
|
+
def region_meaning(color)
|
11
|
+
@colored_regions[color]
|
12
|
+
end
|
13
|
+
|
14
|
+
def line_meaning(color)
|
15
|
+
@colored_lines[color]
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/test/domain/map.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
##
|
2
|
+
# Everyone loves maps.
|
3
|
+
class Map
|
4
|
+
|
5
|
+
attr_reader :type, :center, :units, :legend
|
6
|
+
attr_accessor :notes
|
7
|
+
|
8
|
+
def initialize(type, center, units, legend = :asshole_mapmaker_forgot_legend)
|
9
|
+
@type = type
|
10
|
+
@center = center
|
11
|
+
@units = units
|
12
|
+
@notes = ""
|
13
|
+
@legend = legend
|
14
|
+
end
|
15
|
+
|
16
|
+
def shows_roads?
|
17
|
+
maps_with_roads.include?(type)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def maps_with_roads
|
23
|
+
['road', 'traffic', 'political']
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/test/domain/user.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module UserRecords
|
2
|
+
|
3
|
+
def self.create!
|
4
|
+
users_attributes.each do |attrs|
|
5
|
+
User.create(attrs)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
def self.temporal_reference_point
|
11
|
+
@temporal_reference_point ||= Time.now
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def self.users_attributes
|
16
|
+
[ { id: 1,
|
17
|
+
email: "paulwall@example.com",
|
18
|
+
first_name: "Paul",
|
19
|
+
last_name: "Wall",
|
20
|
+
encrypted_password: "$2a$10$DbRvyFxovWAly4ZCDtcJ6uVhbMGya2iGiLCURhSwM1ZGUyXpM5UiW",
|
21
|
+
sign_in_count: 2,
|
22
|
+
created_at: temporal_reference_point,
|
23
|
+
updated_at: temporal_reference_point,
|
24
|
+
},
|
25
|
+
{ id: 2,
|
26
|
+
email: "gendoarrighetti@example.com",
|
27
|
+
first_name: "Gendo",
|
28
|
+
last_name: "Arrighetti",
|
29
|
+
encrypted_password: "$2a$10$DbRvyFxovWAly4ZCDtcJ6uVhbMGya2iGiLCURhSwM1ZGUyXpM5UiW",
|
30
|
+
sign_in_count: 0,
|
31
|
+
created_at: temporal_reference_point,
|
32
|
+
updated_at: temporal_reference_point,
|
33
|
+
},
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'minitest/reporters'
|
4
|
+
require 'minitest/reporters/turn_again_reporter'
|
5
|
+
Minitest::Reporters.use!(Minitest::Reporters::TurnAgainReporter.new)
|
6
|
+
|
7
|
+
##
|
8
|
+
# The following active_support and active_model files are the specific minimum
|
9
|
+
# dependencies for using ActiveModel::Serializers::JSON
|
10
|
+
require 'active_support/json'
|
11
|
+
require 'active_support/concern'
|
12
|
+
require 'active_support/core_ext/class/attribute'
|
13
|
+
require 'active_model/naming'
|
14
|
+
require 'active_model/serialization'
|
15
|
+
require 'active_model/serializers/json'
|
16
|
+
|
17
|
+
##
|
18
|
+
# And of course, require ourselves.
|
19
|
+
require 'gift_wrap'
|
20
|
+
|
21
|
+
##
|
22
|
+
# Blatantly stolen from ActiveSupport::Testing::Declarative
|
23
|
+
# Allows for test files such as
|
24
|
+
# test "verify something" do
|
25
|
+
# ...
|
26
|
+
# end
|
27
|
+
# which become methods named test_verify_something, leaving a visual difference
|
28
|
+
# between tests themselves and any helper methods declared in the usual
|
29
|
+
# manner of `def some_helper_method`.
|
30
|
+
module DeclarativeTests
|
31
|
+
def test(name, &block)
|
32
|
+
test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
|
33
|
+
defined = instance_method(test_name) rescue false
|
34
|
+
raise "#{test_name} is already defined in #{self}" if defined
|
35
|
+
if block_given?
|
36
|
+
define_method(test_name, &block)
|
37
|
+
else
|
38
|
+
define_method(test_name) do
|
39
|
+
flunk "No implementation provided for #{name}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Minitest::Test
|
46
|
+
extend DeclarativeTests
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# ActiveRecord setup for testing use of GiftWrap::ActiveRecordPresenter
|
51
|
+
#
|
52
|
+
# TODO (possibly):
|
53
|
+
# Have some sort of method for switching on/off inclusion and execution
|
54
|
+
# of active_record in tests. The goal would be to ensure that no tests
|
55
|
+
# unrelated to ActiveRecord accidentally come to rely on its presence, or on
|
56
|
+
# the presence of the friends it pulls in (ActiveModel, ActiveSupport).
|
57
|
+
#
|
58
|
+
# Some ordering of some of these steps is important:
|
59
|
+
# 1. Set up in-memory sqlite3 connection.
|
60
|
+
# 2. Require the model class.
|
61
|
+
# 3. Load the database schema. Doing this before loading the model broke things?
|
62
|
+
# 4. Load a file that creates some user rows and run said creation method.
|
63
|
+
require 'active_record'
|
64
|
+
require 'sqlite3'
|
65
|
+
|
66
|
+
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
67
|
+
require File.join(File.dirname(__FILE__), "domain", "user.rb")
|
68
|
+
require File.join(File.dirname(__FILE__), "database", "schema.rb")
|
69
|
+
require File.join(File.dirname(__FILE__), "fixtures", "user_records.rb")
|
70
|
+
UserRecords.create!
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ActiveRecordPresenterTest < Minitest::Test
|
4
|
+
|
5
|
+
## Test Implementation Classes #################################################
|
6
|
+
|
7
|
+
|
8
|
+
class SimpleUserPresenter
|
9
|
+
include GiftWrap::ActiveRecordPresenter
|
10
|
+
|
11
|
+
unwrap_columns_for ::User
|
12
|
+
|
13
|
+
unwrap_for :initials
|
14
|
+
|
15
|
+
def email_with_display_name
|
16
|
+
"#{first_name} #{last_name} <#{email}>"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
class NoAttributeUserPresenter
|
23
|
+
include GiftWrap::ActiveRecordPresenter
|
24
|
+
unwrap_columns_for ::User, attribute: false
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
class UserPresenterUsingOnly
|
29
|
+
include GiftWrap::ActiveRecordPresenter
|
30
|
+
unwrap_columns_for ::User, attribute: { only: [:first_name, :email, :last_name] }
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
class UserPresenterUsingExcept
|
35
|
+
include GiftWrap::ActiveRecordPresenter
|
36
|
+
unwrap_columns_for ::User, attribute: { except: [:first_name, :email, :last_name] }
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
## Setup Helpers #########################################################
|
41
|
+
|
42
|
+
|
43
|
+
def sample_user
|
44
|
+
User.find(1)
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
## Test Cases ##################################################################
|
49
|
+
|
50
|
+
|
51
|
+
test "can unwrap columns" do
|
52
|
+
paulwall = sample_user
|
53
|
+
presenter = SimpleUserPresenter.new(paulwall)
|
54
|
+
assert(presenter.respond_to?(:email))
|
55
|
+
assert(presenter.respond_to?(:first_name))
|
56
|
+
assert(presenter.respond_to?(:encrypted_password))
|
57
|
+
assert_equal(paulwall.email, presenter.email)
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
test "can respond to additional instance methods" do
|
62
|
+
paulwall = sample_user
|
63
|
+
presenter = SimpleUserPresenter.new(paulwall)
|
64
|
+
assert_equal("Paul Wall <paulwall@example.com>", presenter.email_with_display_name)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
test "can wrap methods as expected of a presenter" do
|
69
|
+
paulwall = sample_user
|
70
|
+
presenter = SimpleUserPresenter.new(paulwall)
|
71
|
+
assert_equal("PW", paulwall.initials)
|
72
|
+
assert_equal("PW", presenter.initials)
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
test "columns are set as presenter attributes by default" do
|
77
|
+
paulwall = sample_user
|
78
|
+
presenter = SimpleUserPresenter.new(paulwall)
|
79
|
+
assert_includes(presenter.attributes.keys, 'email')
|
80
|
+
assert_includes(presenter.attributes.keys, 'created_at')
|
81
|
+
assert_includes(presenter.attributes.keys, 'updated_at')
|
82
|
+
assert_includes(presenter.attributes.keys, 'first_name')
|
83
|
+
assert_includes(presenter.attributes.keys, 'last_name')
|
84
|
+
assert_includes(presenter.attributes.keys, 'sign_in_count' )
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
test "unwrap_columns_for can be asked to set no columns as attributes" do
|
89
|
+
presenter = NoAttributeUserPresenter.new(sample_user)
|
90
|
+
assert_equal({}, presenter.attributes)
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
test "unwrap_columns_for can specify attributes with :only" do
|
95
|
+
presenter = UserPresenterUsingOnly.new(sample_user)
|
96
|
+
assert_includes(presenter.attributes.keys, 'email')
|
97
|
+
assert_includes(presenter.attributes.keys, 'first_name')
|
98
|
+
assert_includes(presenter.attributes.keys, 'last_name')
|
99
|
+
refute_includes(presenter.attributes.keys, 'created_at')
|
100
|
+
refute_includes(presenter.attributes.keys, 'updated_at')
|
101
|
+
refute_includes(presenter.attributes.keys, 'sign_in_count')
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
test "unwrap_columns_for can specify attributes with :except" do
|
106
|
+
presenter = UserPresenterUsingExcept.new(sample_user)
|
107
|
+
assert_includes(presenter.attributes.keys, 'created_at')
|
108
|
+
assert_includes(presenter.attributes.keys, 'updated_at')
|
109
|
+
assert_includes(presenter.attributes.keys, 'sign_in_count')
|
110
|
+
refute_includes(presenter.attributes.keys, 'email')
|
111
|
+
refute_includes(presenter.attributes.keys, 'first_name')
|
112
|
+
refute_includes(presenter.attributes.keys, 'last_name')
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'domain/map'
|
3
|
+
require 'domain/legend'
|
4
|
+
|
5
|
+
class ConfigurationTest < Minitest::Test
|
6
|
+
|
7
|
+
## Setup Helpers #################################################
|
8
|
+
|
9
|
+
##
|
10
|
+
# Since we're reconfiguring module-wide settings, we can't rely on a class defined
|
11
|
+
# at load time to pick up on changes to the configuration during successive test cases.
|
12
|
+
def build_presenter_class
|
13
|
+
Class.new do
|
14
|
+
include GiftWrap::Presenter
|
15
|
+
unwrap_for :type
|
16
|
+
unwrap_for :units, attribute: true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
## Test Cases ##################################################################
|
22
|
+
|
23
|
+
|
24
|
+
test "presenters include serializers when use_serializers is true" do
|
25
|
+
GiftWrap.configure do |config|
|
26
|
+
config.use_serializers = true
|
27
|
+
end
|
28
|
+
map = Map.new("physical", ["here", "there"], "mi")
|
29
|
+
presenter = build_presenter_class.new(map)
|
30
|
+
assert_kind_of(ActiveModel::Serializers::JSON, presenter)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
test "presenters do not include serializers when use_serializers is false" do
|
35
|
+
GiftWrap.configure do |config|
|
36
|
+
config.use_serializers = false
|
37
|
+
end
|
38
|
+
map = Map.new("physical", ["here", "there"], "mi")
|
39
|
+
presenter = build_presenter_class.new(map)
|
40
|
+
refute_kind_of(ActiveModel::Serializers::JSON, presenter)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,259 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'domain/map'
|
3
|
+
require 'domain/legend'
|
4
|
+
|
5
|
+
class PresenterTest < Minitest::Test
|
6
|
+
|
7
|
+
## Test Implementation Classes #################################################
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
# A presenter which adds a few new methods and attributes to a given Map.
|
12
|
+
class SimpleMapPresenter
|
13
|
+
include GiftWrap::Presenter
|
14
|
+
|
15
|
+
attribute :metric?
|
16
|
+
|
17
|
+
unwrap_for :type
|
18
|
+
unwrap_for :units, attribute: true
|
19
|
+
|
20
|
+
def metric?
|
21
|
+
metric_map_units.include?(units)
|
22
|
+
end
|
23
|
+
|
24
|
+
def contains_region?(region_name)
|
25
|
+
false # Implementation not important
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def metric_map_units
|
31
|
+
['m', 'km']
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Gives an explicit name to the wrapped object for reference
|
38
|
+
# internally to the class, and has a method which uses that reference
|
39
|
+
# for use in proving that an internal reference is functioning.
|
40
|
+
class ExplicitReferencePresenter
|
41
|
+
include GiftWrap::Presenter
|
42
|
+
|
43
|
+
wrapped_as :explicit_reference
|
44
|
+
|
45
|
+
def uses_explicit_reference(msg_name)
|
46
|
+
explicit_reference.send(msg_name)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Presenter intended to work with a Legend.
|
53
|
+
class LegendPresenter
|
54
|
+
include GiftWrap::Presenter
|
55
|
+
|
56
|
+
unwrap_for :line_meaning
|
57
|
+
|
58
|
+
attribute :red_lines
|
59
|
+
|
60
|
+
def red_lines
|
61
|
+
line_meaning(:red)
|
62
|
+
end
|
63
|
+
|
64
|
+
def yellow_lines
|
65
|
+
line_meaning(:yellow)
|
66
|
+
end
|
67
|
+
|
68
|
+
def green_lines
|
69
|
+
line_meaning(:green)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Map Presenter which wraps its :legend association, for use in testing associations
|
76
|
+
# being wrapped in a presenter of their own.
|
77
|
+
class LegendaryMapPresenter
|
78
|
+
include GiftWrap::Presenter
|
79
|
+
|
80
|
+
unwrap_for :type, :units
|
81
|
+
|
82
|
+
wrap_association :legend, with: LegendPresenter
|
83
|
+
|
84
|
+
def metric?
|
85
|
+
metric_map_units.include?(units)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def metric_map_units
|
91
|
+
['m', 'km']
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# Another presenter for legends as an alternative to test if overriding association
|
98
|
+
# presenters on a per-instance basis functions.
|
99
|
+
class MisleadingLegendPresenter
|
100
|
+
include GiftWrap::Presenter
|
101
|
+
|
102
|
+
unwrap_for :line_meaning
|
103
|
+
|
104
|
+
def red_lines
|
105
|
+
"no congestion"
|
106
|
+
end
|
107
|
+
|
108
|
+
def yellow_lines
|
109
|
+
"no congestion"
|
110
|
+
end
|
111
|
+
|
112
|
+
def green_lines
|
113
|
+
"no congestion"
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
##
|
119
|
+
# Map Presenter which wraps its :legend association with the name :foobar
|
120
|
+
class FoobarLegendMapPresenter
|
121
|
+
include GiftWrap::Presenter
|
122
|
+
|
123
|
+
unwrap_for :type, :units
|
124
|
+
|
125
|
+
wrap_association :legend, with: LegendPresenter, as: :foobar
|
126
|
+
|
127
|
+
def metric?
|
128
|
+
metric_map_units.include?(units)
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def metric_map_units
|
134
|
+
['m', 'km']
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
## Setup Helpers #########################################################
|
141
|
+
|
142
|
+
|
143
|
+
def physical_map
|
144
|
+
Map.new("physical", ["here", "there"], "mi")
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
def map_with_legend
|
149
|
+
Map.new("traffic", "downtown", "km", traffic_legend)
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
def traffic_legend
|
154
|
+
Legend.new(
|
155
|
+
{ beige: "land",
|
156
|
+
blue: "water"
|
157
|
+
},
|
158
|
+
{ green: "no congestion",
|
159
|
+
yellow: "light congestion",
|
160
|
+
red: "heavy congestion",
|
161
|
+
black: "impassable"
|
162
|
+
})
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
## Test Cases ##################################################################
|
167
|
+
|
168
|
+
|
169
|
+
test "unwrapped methods are delegated properly" do
|
170
|
+
map = physical_map
|
171
|
+
presenter = SimpleMapPresenter.new(map)
|
172
|
+
assert_equal(map.type, presenter.type)
|
173
|
+
assert_equal(map.units, presenter.units)
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
test "methods not explicitly unwrapped are not accessible" do
|
178
|
+
map = physical_map
|
179
|
+
presenter = SimpleMapPresenter.new(map)
|
180
|
+
assert(map.respond_to?(:center))
|
181
|
+
refute(presenter.respond_to?(:center))
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
test "attributes can include unwrapped methods" do
|
186
|
+
attributes = SimpleMapPresenter.new(physical_map).attributes
|
187
|
+
assert_includes(attributes.keys, 'units')
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
test "attributes do not include unwrapped methods by default" do
|
192
|
+
attributes = SimpleMapPresenter.new(physical_map).attributes
|
193
|
+
refute_includes(attributes.keys, 'type')
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
test "attributes hash include explicitly declared attributes" do
|
198
|
+
attributes = SimpleMapPresenter.new(physical_map).attributes
|
199
|
+
assert_includes(attributes.keys, 'metric?')
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
test "can reference a wrapped object internally via wrapped_as name" do
|
204
|
+
map = physical_map
|
205
|
+
presenter = ExplicitReferencePresenter.new(map)
|
206
|
+
assert_equal(map.type, presenter.uses_explicit_reference(:type))
|
207
|
+
assert_equal(map.units, presenter.uses_explicit_reference(:units))
|
208
|
+
assert_raises(NoMethodError) do |variable|
|
209
|
+
presenter.explicit_reference
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
test "associations can be wrapped with their own presenter class" do
|
215
|
+
map = map_with_legend
|
216
|
+
presenter = LegendaryMapPresenter.new(map)
|
217
|
+
assert(map.respond_to?(:legend))
|
218
|
+
assert(presenter.respond_to?(:legend))
|
219
|
+
assert(LegendPresenter === presenter.legend)
|
220
|
+
assert(presenter.legend.respond_to?(:line_meaning))
|
221
|
+
assert(presenter.legend.respond_to?(:red_lines))
|
222
|
+
refute_includes(presenter.legend.attributes.keys, 'line_meaning')
|
223
|
+
assert_includes(presenter.legend.attributes.keys, 'red_lines')
|
224
|
+
assert_equal(presenter.legend.green_lines, 'no congestion')
|
225
|
+
assert_equal(presenter.legend.red_lines, 'heavy congestion')
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
test "associations' class can be specified on a per-instance basis" do
|
230
|
+
map = map_with_legend
|
231
|
+
presenter = LegendaryMapPresenter.new(map, associations: {
|
232
|
+
legend: MisleadingLegendPresenter
|
233
|
+
})
|
234
|
+
assert(map.respond_to?(:legend))
|
235
|
+
assert(presenter.respond_to?(:legend))
|
236
|
+
assert(MisleadingLegendPresenter === presenter.legend)
|
237
|
+
assert(presenter.legend.respond_to?(:line_meaning))
|
238
|
+
assert(presenter.legend.respond_to?(:red_lines))
|
239
|
+
assert_equal(presenter.legend.green_lines, 'no congestion')
|
240
|
+
assert_equal(presenter.legend.red_lines, 'no congestion')
|
241
|
+
end
|
242
|
+
|
243
|
+
|
244
|
+
test "associations' name can be something other than assoication name" do
|
245
|
+
map = map_with_legend
|
246
|
+
presenter = FoobarLegendMapPresenter.new(map)
|
247
|
+
assert(map.respond_to?(:legend))
|
248
|
+
assert(presenter.respond_to?(:foobar))
|
249
|
+
assert(LegendPresenter === presenter.foobar)
|
250
|
+
# Most of this mirrors the other association tests for good measure.
|
251
|
+
assert(presenter.foobar.respond_to?(:line_meaning))
|
252
|
+
assert(presenter.foobar.respond_to?(:red_lines))
|
253
|
+
refute_includes(presenter.foobar.attributes.keys, 'line_meaning')
|
254
|
+
assert_includes(presenter.foobar.attributes.keys, 'red_lines')
|
255
|
+
assert_equal(presenter.foobar.green_lines, 'no congestion')
|
256
|
+
assert_equal(presenter.foobar.red_lines, 'heavy congestion')
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
metadata
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gift_wrap
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul Kwiatkowski
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activemodel
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest-reporters
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: turn-again-reporter
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.1'
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 1.1.0
|
79
|
+
type: :development
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - "~>"
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '1.1'
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 1.1.0
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: activerecord
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '4.0'
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 4.0.0
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - "~>"
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '4.0'
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: 4.0.0
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: sqlite3
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - "~>"
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '1.3'
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: 1.3.0
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '1.3'
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: 1.3.0
|
129
|
+
description: A simple Ruby presenter library, for those who enjoy a strong separation
|
130
|
+
of concerns. You include a module, call some class-level macro-style methods, and
|
131
|
+
suddenly you're presenting for a wrapped object. No magic. If your knowledge of
|
132
|
+
pattern names comes from the Rails ecosystem, you might have used the popular Draper
|
133
|
+
'decorator' library. Think of this like that one, except the term 'presenter' is
|
134
|
+
a better fit.
|
135
|
+
email:
|
136
|
+
- paul@groupraise.com
|
137
|
+
executables: []
|
138
|
+
extensions: []
|
139
|
+
extra_rdoc_files: []
|
140
|
+
files:
|
141
|
+
- Gemfile
|
142
|
+
- Gemfile.lock
|
143
|
+
- LICENSE.md
|
144
|
+
- README.md
|
145
|
+
- Rakefile
|
146
|
+
- lib/gift_wrap.rb
|
147
|
+
- lib/gift_wrap/active_record_presenter.rb
|
148
|
+
- lib/gift_wrap/configuration.rb
|
149
|
+
- lib/gift_wrap/presenter.rb
|
150
|
+
- lib/gift_wrap/version.rb
|
151
|
+
- test/database/schema.rb
|
152
|
+
- test/domain/legend.rb
|
153
|
+
- test/domain/map.rb
|
154
|
+
- test/domain/user.rb
|
155
|
+
- test/fixtures/user_records.rb
|
156
|
+
- test/test_helper.rb
|
157
|
+
- test/unit/active_record_presenter_test.rb
|
158
|
+
- test/unit/configuration_test.rb
|
159
|
+
- test/unit/presenter_test.rb
|
160
|
+
homepage: https://github.com/swifthand/adalog
|
161
|
+
licenses:
|
162
|
+
- Revised BSD, see LICENSE.md
|
163
|
+
metadata: {}
|
164
|
+
post_install_message:
|
165
|
+
rdoc_options: []
|
166
|
+
require_paths:
|
167
|
+
- lib
|
168
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
|
+
requirements:
|
175
|
+
- - ">="
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '0'
|
178
|
+
requirements: []
|
179
|
+
rubyforge_project:
|
180
|
+
rubygems_version: 2.4.8
|
181
|
+
signing_key:
|
182
|
+
specification_version: 4
|
183
|
+
summary: A simple Ruby presenter library, for those who enjoy a strong separation
|
184
|
+
of concerns.
|
185
|
+
test_files:
|
186
|
+
- test/database/schema.rb
|
187
|
+
- test/domain/legend.rb
|
188
|
+
- test/domain/map.rb
|
189
|
+
- test/domain/user.rb
|
190
|
+
- test/fixtures/user_records.rb
|
191
|
+
- test/test_helper.rb
|
192
|
+
- test/unit/active_record_presenter_test.rb
|
193
|
+
- test/unit/configuration_test.rb
|
194
|
+
- test/unit/presenter_test.rb
|