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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fdd0c7efa14f672dba1fd48fb7e930fb382628cb552e7695601e26cd1e799f82
4
- data.tar.gz: 7bf5638cfd3896aa45f7746154e8b6d41d796d152233b33d9e3506682cf75eb8
3
+ metadata.gz: 2ed4527a2a221a276e499bd089f9dc3006ce9cd77df82e3942bf315dc911a0fe
4
+ data.tar.gz: 44872f2fe052f02eaef244303814a9e62123238d879c140c6ce29a7e010c4f77
5
5
  SHA512:
6
- metadata.gz: 6d354a1299513afbfc555bd93f9d5a212d038a047f3da5d6c0a77061b2249ba64f130e623e533de6bc7546c1c01a6a1af76a8a098a939381878a0bbb79249342
7
- data.tar.gz: '048eb40b6d05b93227d5c318cdb01594b2df688cb68dfde1c76e8019090281b12fc30b080e3c406a7355197e0d1b0d34e51dc07485efa174727753e39ce53f28'
6
+ metadata.gz: 4157653ae694c4c5c60a2dd203037cbc644792a8a32524d96864c71b785a072ce9e34776f5aad38ae390be7ce0be5588322a6a3a0a43e21688e741e5e7c0d6c3
7
+ data.tar.gz: 05537aca1745b016fef2660ed2693dfac117c3f3c1df85966549be0955fc57ca2a777c930f39f61dc8ce16e4262c2a8b2ec0a672accc41c8a7331d3042e30946
@@ -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.2.0
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: 2020-03-04 00:00:00.000000000 Z
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.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