activerepresenter 0.2.0 → 0.2.5
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 +4 -4
- data/activerepresenter.gemspec +2 -2
- data/lib/active_representer/base.rb +115 -43
- data/test/attr_collection_test.rb +11 -1
- data/test/attr_one_test.rb +44 -0
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ed4527a2a221a276e499bd089f9dc3006ce9cd77df82e3942bf315dc911a0fe
|
4
|
+
data.tar.gz: 44872f2fe052f02eaef244303814a9e62123238d879c140c6ce29a7e010c4f77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4157653ae694c4c5c60a2dd203037cbc644792a8a32524d96864c71b785a072ce9e34776f5aad38ae390be7ce0be5588322a6a3a0a43e21688e741e5e7c0d6c3
|
7
|
+
data.tar.gz: 05537aca1745b016fef2660ed2693dfac117c3f3c1df85966549be0955fc57ca2a777c930f39f61dc8ce16e4262c2a8b2ec0a672accc41c8a7331d3042e30946
|
data/activerepresenter.gemspec
CHANGED
@@ -24,8 +24,8 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.test_files = s.files.grep(/^test/)
|
25
25
|
|
26
26
|
s.add_dependency "bundler", ">= 1.3"
|
27
|
-
s.add_dependency "activemodel", ">= 5.2", "< 6.
|
28
|
-
s.add_dependency "activesupport", ">= 5.2", "< 6.
|
27
|
+
s.add_dependency "activemodel", ">= 5.2", "< 6.2"
|
28
|
+
s.add_dependency "activesupport", ">= 5.2", "< 6.2"
|
29
29
|
s.add_development_dependency "rake", ">= 12.3.3"
|
30
30
|
s.add_development_dependency "test-unit", ">= 3.3"
|
31
31
|
end
|
@@ -4,69 +4,141 @@ require "active_model"
|
|
4
4
|
require "active_support"
|
5
5
|
|
6
6
|
module ActiveRepresenter
|
7
|
+
# == Action \Representer \Base
|
8
|
+
#
|
9
|
+
# This is a base class for a representer (wrapped object).
|
10
|
+
# It wraps the original object as `wrapped` attribute and
|
11
|
+
# you can add custom methods to the class (using the decorator pattern).
|
12
|
+
#
|
13
|
+
# In addition, `attr_field` / `attr_collection` can be used for attributes.
|
14
|
+
#
|
15
|
+
# attr_field:
|
16
|
+
# Declare additional field and type to the objects.
|
17
|
+
# You can get / set field's value (converted to corresponding).
|
18
|
+
# It uses ActiveModel::Attributes internally.
|
19
|
+
# See examples: AttrFieldTest in test/attr_field_test.
|
20
|
+
#
|
21
|
+
# attr_one:
|
22
|
+
# Declare an associated object like has one association.
|
23
|
+
# If a representer for the object is found, the object will be wrapped by the representer.
|
24
|
+
# See examples: AttrOneTest in test/attr_one_test.
|
25
|
+
#
|
26
|
+
# attr_many:
|
27
|
+
# Declare associated objects like has many association.
|
28
|
+
# If a representer for the objects is found, the objects will be wrapped by the representer.
|
29
|
+
# See examples: AttrCollectionTest in test/attr_collection_test.
|
7
30
|
class Base
|
8
31
|
include ActiveModel::Model
|
9
32
|
include ActiveModel::Attributes
|
10
33
|
|
11
34
|
attribute :wrapped
|
35
|
+
class_attribute :ones, default: {}
|
12
36
|
class_attribute :collections, default: {}
|
13
37
|
|
14
38
|
delegate_missing_to :wrapped
|
15
39
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
instance
|
40
|
+
def self.inherited(subclass)
|
41
|
+
subclass.ones = {}
|
42
|
+
subclass.collections = {}
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.wrap(wrapped)
|
46
|
+
instance = new
|
47
|
+
instance.wrapped = wrapped
|
48
|
+
|
49
|
+
one_names.each do |one_name|
|
50
|
+
next if wrapped[one_name].nil?
|
51
|
+
representer_klass = ones[one_name]
|
52
|
+
one_value = \
|
53
|
+
if representer_klass
|
54
|
+
representer_klass.wrap(wrapped[one_name])
|
55
|
+
else
|
56
|
+
wrapped[one_name]
|
57
|
+
end
|
58
|
+
instance.instance_variable_set("@#{one_name}", one_value)
|
35
59
|
end
|
36
60
|
|
37
|
-
|
38
|
-
|
61
|
+
collection_names.each do |collection_name|
|
62
|
+
next if wrapped[collection_name].nil?
|
63
|
+
representer_klass = collections[collection_name]
|
64
|
+
collection_value = \
|
65
|
+
if representer_klass
|
66
|
+
wrapped[collection_name].map { |item| representer_klass.wrap(item) }
|
67
|
+
else
|
68
|
+
wrapped[collection_name]
|
69
|
+
end
|
70
|
+
instance.instance_variable_set("@#{collection_name}", collection_value)
|
39
71
|
end
|
40
72
|
|
41
|
-
|
42
|
-
|
43
|
-
raise ArgumentError.new("collection's name must be a Symbol or a String")
|
44
|
-
end
|
45
|
-
representer_name = \
|
46
|
-
options[:representer_name] ? options[:representer_name] : guess_representrer_name(name.to_s)
|
47
|
-
raise ArgumentError.new("representer_name must be a String") unless representer_name.is_a?(String)
|
48
|
-
begin
|
49
|
-
representer = representer_name.constantize
|
50
|
-
collections[name.to_sym] = representer
|
51
|
-
rescue NameError => e
|
52
|
-
collections[name.to_sym] = nil
|
53
|
-
end
|
54
|
-
class_eval do
|
55
|
-
attr_reader name.to_sym
|
56
|
-
end
|
73
|
+
attribute_names.each do |attribute_name|
|
74
|
+
instance.send("#{attribute_name}=", wrapped.send(attribute_name))
|
57
75
|
end
|
58
76
|
|
59
|
-
|
60
|
-
|
77
|
+
instance
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.attr_field(name, type = Type::Value.new, **options)
|
81
|
+
attribute(name, type, **options)
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.attr_one(name, **options)
|
85
|
+
check_name_type(name)
|
86
|
+
representer_name = specify_or_guess_representer_name(options[:representer_name], name)
|
87
|
+
|
88
|
+
begin
|
89
|
+
representer = representer_name.constantize
|
90
|
+
ones[name.to_sym] = representer
|
91
|
+
rescue NameError
|
92
|
+
ones[name.to_sym] = nil
|
93
|
+
end
|
94
|
+
|
95
|
+
class_eval do
|
96
|
+
attr_reader name.to_sym
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.attr_collection(name, **options)
|
101
|
+
check_name_type(name)
|
102
|
+
representer_name = specify_or_guess_representer_name(options[:representer_name], name)
|
103
|
+
|
104
|
+
begin
|
105
|
+
representer = representer_name.constantize
|
106
|
+
collections[name.to_sym] = representer
|
107
|
+
rescue NameError
|
108
|
+
collections[name.to_sym] = nil
|
61
109
|
end
|
62
110
|
|
63
|
-
|
64
|
-
|
111
|
+
class_eval do
|
112
|
+
attr_reader name.to_sym
|
65
113
|
end
|
114
|
+
end
|
115
|
+
|
116
|
+
singleton_class.send(:alias_method, :attr_many, :attr_collection)
|
117
|
+
|
118
|
+
def self.one_names
|
119
|
+
ones.keys
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.collection_names
|
123
|
+
collections.keys
|
124
|
+
end
|
66
125
|
|
67
|
-
|
68
|
-
|
126
|
+
def self.attribute_names
|
127
|
+
attribute_types.keys - ["wrapped"]
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.check_name_type(name)
|
131
|
+
unless name.is_a?(Symbol) || name.is_a?(String)
|
132
|
+
raise ArgumentError.new("collection's name must be a Symbol or a String")
|
69
133
|
end
|
70
134
|
end
|
135
|
+
|
136
|
+
def self.guess_representrer_name(name)
|
137
|
+
"#{name.singularize.camelize}Representer"
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.specify_or_guess_representer_name(specified_name, wrapped_name)
|
141
|
+
specified_name ? specified_name.to_s : guess_representrer_name(wrapped_name.to_s)
|
142
|
+
end
|
71
143
|
end
|
72
144
|
end
|
@@ -11,7 +11,7 @@ end
|
|
11
11
|
|
12
12
|
class UserRepresenter < ActiveRepresenter::Base
|
13
13
|
attr_collection :activities
|
14
|
-
|
14
|
+
attr_many :notifications
|
15
15
|
|
16
16
|
def full_name
|
17
17
|
"#{first_name} #{last_name}"
|
@@ -71,4 +71,14 @@ class AttrCollectionTest < Test::Unit::TestCase
|
|
71
71
|
notification = representer.notifications.first
|
72
72
|
assert_instance_of(OpenStruct, notification)
|
73
73
|
end
|
74
|
+
|
75
|
+
test "representer class include :activities and :notifications in collection_names array" do
|
76
|
+
collection_names = UserRepresenter.collection_names
|
77
|
+
assert_equal(collection_names, [:activities, :notifications])
|
78
|
+
end
|
79
|
+
|
80
|
+
test "base class doesn't have any entries in collection_names array" do
|
81
|
+
collection_names = ActiveRepresenter::Base.collection_names
|
82
|
+
assert_equal(collection_names, [])
|
83
|
+
end
|
74
84
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "ostruct"
|
3
|
+
require "active_support/time"
|
4
|
+
require_relative "../lib/active_representer/base.rb"
|
5
|
+
|
6
|
+
class ProfileRepresenter < ActiveRepresenter::Base
|
7
|
+
def email_sent_on
|
8
|
+
email_sent_at.to_date
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class UserRepresenter < ActiveRepresenter::Base
|
13
|
+
attr_one :profile
|
14
|
+
end
|
15
|
+
|
16
|
+
class AttrOneTest < Test::Unit::TestCase
|
17
|
+
test "profile is represented" do
|
18
|
+
user = OpenStruct.new(
|
19
|
+
profile: OpenStruct.new(email_sent_at: Time.now)
|
20
|
+
)
|
21
|
+
representer = UserRepresenter.wrap(user)
|
22
|
+
profile = representer.profile
|
23
|
+
assert_instance_of(ProfileRepresenter, profile)
|
24
|
+
end
|
25
|
+
|
26
|
+
test "profile.email_sent_on is Date.today" do
|
27
|
+
user = OpenStruct.new(
|
28
|
+
profile: OpenStruct.new(email_sent_at: Time.now)
|
29
|
+
)
|
30
|
+
representer = UserRepresenter.wrap(user)
|
31
|
+
profile = representer.profile
|
32
|
+
assert_equal(profile.email_sent_on, Date.today)
|
33
|
+
end
|
34
|
+
|
35
|
+
test "representer class include profile in one_names array" do
|
36
|
+
one_names = UserRepresenter.one_names
|
37
|
+
assert_equal(one_names, [:profile])
|
38
|
+
end
|
39
|
+
|
40
|
+
test "base class doesn't include profile in one_names array" do
|
41
|
+
one_names = ActiveRepresenter::Base.one_names
|
42
|
+
assert_equal(one_names, [])
|
43
|
+
end
|
44
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerepresenter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryo Hashimoto
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
version: '5.2'
|
34
34
|
- - "<"
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version: '6.
|
36
|
+
version: '6.2'
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '5.2'
|
44
44
|
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '6.
|
46
|
+
version: '6.2'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: activesupport
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
version: '5.2'
|
54
54
|
- - "<"
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version: '6.
|
56
|
+
version: '6.2'
|
57
57
|
type: :runtime
|
58
58
|
prerelease: false
|
59
59
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -63,7 +63,7 @@ dependencies:
|
|
63
63
|
version: '5.2'
|
64
64
|
- - "<"
|
65
65
|
- !ruby/object:Gem::Version
|
66
|
-
version: '6.
|
66
|
+
version: '6.2'
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
68
|
name: rake
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -105,6 +105,7 @@ files:
|
|
105
105
|
- lib/activerepresenter.rb
|
106
106
|
- test/attr_collection_test.rb
|
107
107
|
- test/attr_field_test.rb
|
108
|
+
- test/attr_one_test.rb
|
108
109
|
- test/base_test.rb
|
109
110
|
- test/inheritance_test.rb
|
110
111
|
homepage: https://github.com/ryohashimoto/lightrails
|
@@ -126,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
127
|
- !ruby/object:Gem::Version
|
127
128
|
version: 1.8.11
|
128
129
|
requirements: []
|
129
|
-
rubygems_version: 3.
|
130
|
+
rubygems_version: 3.1.4
|
130
131
|
signing_key:
|
131
132
|
specification_version: 4
|
132
133
|
summary: Active Representer provides model objects by decorating objects (part of
|
@@ -134,5 +135,6 @@ summary: Active Representer provides model objects by decorating objects (part o
|
|
134
135
|
test_files:
|
135
136
|
- test/attr_collection_test.rb
|
136
137
|
- test/attr_field_test.rb
|
138
|
+
- test/attr_one_test.rb
|
137
139
|
- test/base_test.rb
|
138
140
|
- test/inheritance_test.rb
|