Skip to content

Commit e9c9713

Browse files
committed
[Refactor] Remove OpenStruct usage
Also added more test cases for conditional attributes.
1 parent 523251d commit e9c9713

File tree

5 files changed

+81
-27
lines changed

5 files changed

+81
-27
lines changed

.rubocop.yml

-10
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,6 @@ Minitest/NoTestCases:
9292
Exclude:
9393
- 'test/dependencies/test_dependencies.rb'
9494

95-
# We need to use `OpenStruct` to wrap object in ConfitionalAttribute
96-
Performance/OpenStruct:
97-
Exclude:
98-
- 'lib/alba/conditional_attribute.rb'
99-
10095
# We need to eval resource code to test errors on resource classes
10196
Security/Eval:
10297
Exclude:
@@ -145,11 +140,6 @@ Style/MethodCallWithArgsParentheses:
145140
Style/MissingElse:
146141
EnforcedStyle: case
147142

148-
# We need to use `OpenStruct` to wrap object in ConfitionalAttribute
149-
Style/OpenStructUse:
150-
Exclude:
151-
- 'lib/alba/conditional_attribute.rb'
152-
153143
# It's example code, please forgive us
154144
Style/OptionalBooleanParameter:
155145
Exclude:

alba.gemspec

-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,4 @@ Gem::Specification.new do |spec|
2525
spec.bindir = 'exe'
2626
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
2727
spec.require_paths = ['lib']
28-
29-
spec.add_dependency "ostruct", "~> 0.6"
3028
end

lib/alba/conditional_attribute.rb

+10-13
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
require_relative 'association'
44
require_relative 'constants'
5-
require 'ostruct'
65

76
module Alba
87
# Represents attribute with `if` option
@@ -26,7 +25,7 @@ def with_passing_condition(resource:, object: nil)
2625
fetched_attribute = yield(@body)
2726
return fetched_attribute unless with_two_arity_proc_condition
2827

29-
return Alba::REMOVE_KEY unless resource.instance_exec(object, objectize(fetched_attribute), &@condition)
28+
return Alba::REMOVE_KEY unless resource.instance_exec(object, second_object(object), &@condition)
3029

3130
fetched_attribute
3231
end
@@ -51,17 +50,15 @@ def with_two_arity_proc_condition
5150
@condition.is_a?(Proc) && @condition.arity >= 2
5251
end
5352

54-
# OpenStruct is used as a simple solution for converting Hash or Array of Hash into an object
55-
# Using OpenStruct is not good in general, but in this case there's no other solution
56-
def objectize(fetched_attribute)
57-
return fetched_attribute unless @body.is_a?(Alba::Association)
58-
59-
if fetched_attribute.is_a?(Array)
60-
fetched_attribute.map do |hash|
61-
OpenStruct.new(hash)
62-
end
63-
else
64-
OpenStruct.new(fetched_attribute)
53+
def second_object(object)
54+
case @body
55+
when Symbol, Alba::Association, Alba::TypedAttribute
56+
object.__send__(@body.name)
57+
when Alba::NestedAttribute
58+
nil
59+
when Proc
60+
@body.call(object)
61+
else raise Alba::Error, "Unreachable code, @body is: #{@body.inspect}"
6562
end
6663
end
6764
end

lib/alba/typed_attribute.rb

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ module Alba
44
# Representing typed attributes to encapsulate logic about types
55
# @api private
66
class TypedAttribute
7+
attr_reader :name
8+
79
# @param name [Symbol, String]
810
# @param type [Symbol, Class]
911
# @param converter [Proc]

test/usecases/conditional_attributes_test.rb

+69-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class UserResource1 < UserResource
5555
end
5656

5757
class UserResource2 < UserResource
58-
attribute :username, if: proc { |user| user.id == 1 } do
58+
attribute :username, if: proc { |user, _username| user.id == 1 } do
5959
'username'
6060
end
6161
end
@@ -248,6 +248,43 @@ def test_conditional_attributes_with_if_and_resource_method
248248
)
249249
end
250250

251+
class UserResource14 < UserResource
252+
one :profile, resource: ProfileResource, key: :my_profile, if: proc { |_user, profile| profile.email.end_with?('com') }
253+
end
254+
255+
def test_conditional_one_with_key_option
256+
assert_equal(
257+
'{"id":1,"my_profile":{"email":"test@example.com"}}',
258+
UserResource14.new(@user).serialize
259+
)
260+
user = User.new(2, 'Foo')
261+
profile = Profile.new(2, 'test@example.org')
262+
user.profile = profile
263+
assert_equal(
264+
'{"id":2}',
265+
UserResource14.new(user).serialize
266+
)
267+
end
268+
269+
class UserResource15 < UserResource
270+
many :articles,
271+
proc { |articles| articles }, # dummy
272+
resource: ArticleResource,
273+
if: proc { |_user, articles| !articles.empty? }
274+
end
275+
276+
def test_conditional_many_with_condition_proc
277+
assert_equal(
278+
'{"id":1,"articles":[{"title":"Hello World!"}]}',
279+
UserResource15.new(@user).serialize
280+
)
281+
user = User.new(2, 'Foo')
282+
assert_equal(
283+
'{"id":2}',
284+
UserResource15.new(user).serialize
285+
)
286+
end
287+
251288
class Foo
252289
attr_reader :id, :name
253290

@@ -262,7 +299,7 @@ class FooResource
262299

263300
attributes :id
264301

265-
nested :bar, if: proc { params[:flag] } do
302+
nested :bar, if: proc { |foo, _| params[:flag] || foo.id == 42 } do # dummy second parameter to test it doesn't raise an exception
266303
attributes :name
267304
attribute :baz do
268305
'baz'
@@ -280,6 +317,11 @@ def test_conditional_attributes_with_nested_attributes
280317
'{"id":1}',
281318
FooResource.new(foo, params: {flag: false}).serialize
282319
)
320+
foo42 = Foo.new(42, 'name')
321+
assert_equal(
322+
'{"id":42,"bar":{"name":"name","baz":"baz"}}',
323+
FooResource.new(foo42, params: {flag: false}).serialize
324+
)
283325
end
284326

285327
class FooTypedResource
@@ -323,4 +365,29 @@ def test_conditional_attributes_with_type_and_resource_method
323365
FooTypedResource2.new(foo, params: {flag: false}).serialize
324366
)
325367
end
368+
369+
class FooTypedResource3
370+
include Alba::Resource
371+
372+
attributes id: Integer
373+
attributes name: :String, if: proc { |foo, name| foo.id == 1 || name == 'my name' }
374+
end
375+
376+
def test_conditional_attributes_with_type_with_two_arity_condition
377+
foo1 = Foo.new(1, 'name')
378+
assert_equal(
379+
'{"id":1,"name":"name"}',
380+
FooTypedResource3.new(foo1).serialize
381+
)
382+
foo2 = Foo.new(2, 'name')
383+
assert_equal(
384+
'{"id":2}',
385+
FooTypedResource3.new(foo2).serialize
386+
)
387+
foo3 = Foo.new(3, 'my name')
388+
assert_equal(
389+
'{"id":3,"name":"my name"}',
390+
FooTypedResource3.new(foo3).serialize
391+
)
392+
end
326393
end

0 commit comments

Comments
 (0)