activerepresenter 0.1.0.1 → 0.2.4

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: 4d2778a2232c8cae0dd21c86b03e0dafd3a0b399b85a85dc2a3085bf92634214
4
- data.tar.gz: ffd532d19507e1c055bc2198861725fe4d262ca5947876cd88fe7e86768ff78d
3
+ metadata.gz: 1f849d3a36907bc1ffef6b30a003ca7789d31ef0e14305434d33e90965b6b7ab
4
+ data.tar.gz: 0befc9d17bca688690c4a462a1d7fe6f0930f6177d4a4e9320e82af297de2d4b
5
5
  SHA512:
6
- metadata.gz: 838daa68b45ffa1e4b5b3a388f925526e18ef03eea9952823c68ae581974d846497877c9f9104a889fa0ae0b278198a283a13c81ad31152ee3029dffa135d6c4
7
- data.tar.gz: 5b82aa498e193fb0c73bdccccedf0b5aa7ebd30a1a720e863479afe634d0567fcb7b0f773d602ded3f3fe51d147684ce653152f20800226de4586c1dacf1b1e8
6
+ metadata.gz: 05bf247d43d821f72452b7643f6a63b3b9d196cc2b033c4ce566cc644a7de840ec712b1e778739b98ff22e0dcacca697ca656e42ce2c237beacb75c3e42e737d
7
+ data.tar.gz: 4d15d35daa8d2d4cd5ddd10b824834c255d2256c18b73bfd484064995118d035e3c90f9a4fbbf09ff6475f3928fe60a4210febd73f45fbafaa3111fd6bf8e771
@@ -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.1"
28
- s.add_dependency "activesupport", ">= 5.2", "< 6.1"
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
- class << self
17
- def wrap(wrapped)
18
- instance = new
19
- instance.wrapped = wrapped
20
- collection_names.each do |collection_name|
21
- next if wrapped[collection_name].nil?
22
- representer_klass = collections[collection_name]
23
- collection_value = \
24
- if representer_klass
25
- wrapped[collection_name].map { |item| representer_klass.wrap(item) }
26
- else
27
- wrapped[collection_name]
28
- end
29
- instance.instance_variable_set("@#{collection_name}", collection_value)
30
- end
31
- attribute_names.each do |attribute_name|
32
- instance.send("#{attribute_name}=", wrapped.send(attribute_name))
33
- end
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
- def attr_field(name, type = Type::Value.new, **options)
38
- attribute(name, type, **options)
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
- def attr_collection(name, **options)
42
- unless name.is_a?(Symbol) || name.is_a?(String)
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
- def collection_names
60
- collections.keys
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
- def attribute_names
64
- attribute_types.keys - ["wrapped"]
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
- def guess_representrer_name(name)
68
- "#{name.singularize.camelize}Representer"
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
- attr_collection :notifications
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.1.0.1
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryo Hashimoto
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-02 00:00:00.000000000 Z
11
+ date: 2021-04-11 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.1'
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.1'
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.1'
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.1'
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.0.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