alba 0.13.0 → 1.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 +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +26 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/dependabot.yml +26 -0
- data/.github/workflows/main.yml +34 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +33 -2
- data/.yardopts +2 -0
- data/CHANGELOG.md +35 -0
- data/Gemfile +10 -4
- data/README.md +311 -43
- data/Rakefile +4 -1
- data/SECURITY.md +12 -0
- data/alba.gemspec +2 -2
- data/benchmark/local.rb +341 -0
- data/codecov.yml +8 -0
- data/gemfiles/all.gemfile +19 -0
- data/gemfiles/without_active_support.gemfile +17 -0
- data/gemfiles/without_oj.gemfile +17 -0
- data/lib/alba.rb +56 -19
- data/lib/alba/association.rb +22 -7
- data/lib/alba/key_transformer.rb +2 -1
- data/lib/alba/many.rb +8 -4
- data/lib/alba/one.rb +8 -4
- data/lib/alba/resource.rb +180 -59
- data/lib/alba/version.rb +1 -1
- data/sider.yml +2 -4
- metadata +16 -8
- data/.travis.yml +0 -10
- data/Gemfile.lock +0 -92
- data/lib/alba/serializer.rb +0 -77
data/lib/alba.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require_relative 'alba/version'
|
2
|
-
require_relative 'alba/serializer'
|
3
2
|
require_relative 'alba/resource'
|
4
3
|
|
5
4
|
# Core module
|
@@ -10,9 +9,11 @@ module Alba
|
|
10
9
|
# Error class for backend which is not supported
|
11
10
|
class UnsupportedBackend < Error; end
|
12
11
|
|
12
|
+
# Error class for type which is not supported
|
13
|
+
class UnsupportedType < Error; end
|
14
|
+
|
13
15
|
class << self
|
14
|
-
attr_reader :backend, :encoder
|
15
|
-
attr_accessor :default_serializer
|
16
|
+
attr_reader :backend, :encoder, :inferring, :_on_error, :transforming_root_key
|
16
17
|
|
17
18
|
# Set the backend, which actually serializes object into JSON
|
18
19
|
#
|
@@ -28,25 +29,64 @@ module Alba
|
|
28
29
|
# Serialize the object with inline definitions
|
29
30
|
#
|
30
31
|
# @param object [Object] the object to be serialized
|
31
|
-
# @param
|
32
|
+
# @param key [Symbol]
|
32
33
|
# @param block [Block] resource block
|
33
34
|
# @return [String] serialized JSON string
|
34
35
|
# @raise [ArgumentError] if block is absent or `with` argument's type is wrong
|
35
|
-
def serialize(object,
|
36
|
+
def serialize(object, key: nil, &block)
|
36
37
|
raise ArgumentError, 'Block required' unless block
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
resource.
|
39
|
+
klass = Class.new
|
40
|
+
klass.include(Alba::Resource)
|
41
|
+
klass.class_eval(&block)
|
42
|
+
resource = klass.new(object)
|
43
|
+
resource.serialize(key: key)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Enable inference for key and resource name
|
47
|
+
def enable_inference!
|
48
|
+
begin
|
49
|
+
require 'active_support/inflector'
|
50
|
+
rescue LoadError
|
51
|
+
raise ::Alba::Error, 'To enable inference, please install `ActiveSupport` gem.'
|
52
|
+
end
|
53
|
+
@inferring = true
|
54
|
+
end
|
55
|
+
|
56
|
+
# Disable inference for key and resource name
|
57
|
+
def disable_inference!
|
58
|
+
@inferring = false
|
59
|
+
end
|
60
|
+
|
61
|
+
# Set error handler
|
62
|
+
#
|
63
|
+
# @param [Symbol] handler
|
64
|
+
# @param [Block]
|
65
|
+
def on_error(handler = nil, &block)
|
66
|
+
raise ArgumentError, 'You cannot specify error handler with both Symbol and block' if handler && block
|
67
|
+
raise ArgumentError, 'You must specify error handler with either Symbol or block' unless handler || block
|
68
|
+
|
69
|
+
@_on_error = handler || block
|
70
|
+
end
|
71
|
+
|
72
|
+
# Enable root key transformation
|
73
|
+
def enable_root_key_transformation!
|
74
|
+
@transforming_root_key = true
|
75
|
+
end
|
76
|
+
|
77
|
+
# Disable root key transformation
|
78
|
+
def disable_root_key_transformation!
|
79
|
+
@transforming_root_key = false
|
42
80
|
end
|
43
81
|
|
44
82
|
private
|
45
83
|
|
46
84
|
def set_encoder
|
47
85
|
@encoder = case @backend
|
48
|
-
when :oj
|
86
|
+
when :oj, :oj_strict
|
49
87
|
try_oj
|
88
|
+
when :oj_rails
|
89
|
+
try_oj(mode: :rails)
|
50
90
|
when :active_support
|
51
91
|
try_active_support
|
52
92
|
when nil, :default, :json
|
@@ -56,10 +96,11 @@ module Alba
|
|
56
96
|
end
|
57
97
|
end
|
58
98
|
|
59
|
-
def try_oj
|
99
|
+
def try_oj(mode: :strict)
|
60
100
|
require 'oj'
|
61
|
-
->(hash) { Oj.dump(hash, mode:
|
101
|
+
->(hash) { Oj.dump(hash, mode: mode) }
|
62
102
|
rescue LoadError
|
103
|
+
Kernel.warn '`Oj` is not installed, falling back to default JSON encoder.'
|
63
104
|
default_encoder
|
64
105
|
end
|
65
106
|
|
@@ -67,6 +108,7 @@ module Alba
|
|
67
108
|
require 'active_support/json'
|
68
109
|
->(hash) { ActiveSupport::JSON.encode(hash) }
|
69
110
|
rescue LoadError
|
111
|
+
Kernel.warn '`ActiveSupport` is not installed, falling back to default JSON encoder.'
|
70
112
|
default_encoder
|
71
113
|
end
|
72
114
|
|
@@ -76,14 +118,9 @@ module Alba
|
|
76
118
|
JSON.dump(hash)
|
77
119
|
end
|
78
120
|
end
|
79
|
-
|
80
|
-
def resource_class
|
81
|
-
@resource_class ||= begin
|
82
|
-
klass = Class.new
|
83
|
-
klass.include(Alba::Resource)
|
84
|
-
end
|
85
|
-
end
|
86
121
|
end
|
87
122
|
|
88
123
|
@encoder = default_encoder
|
124
|
+
@_on_error = :raise
|
125
|
+
@transforming_root_key = false # TODO: This will be true since 2.0
|
89
126
|
end
|
data/lib/alba/association.rb
CHANGED
@@ -2,25 +2,40 @@ module Alba
|
|
2
2
|
# Base class for `One` and `Many`
|
3
3
|
# Child class should implement `to_hash` method
|
4
4
|
class Association
|
5
|
+
attr_reader :object
|
6
|
+
|
5
7
|
# @param name [Symbol] name of the method to fetch association
|
6
8
|
# @param condition [Proc] a proc filtering data
|
7
9
|
# @param resource [Class<Alba::Resource>] a resource class for the association
|
8
10
|
# @param block [Block] used to define resource when resource arg is absent
|
9
|
-
def initialize(name:, condition: nil, resource: nil, &block)
|
11
|
+
def initialize(name:, condition: nil, resource: nil, nesting: nil, &block)
|
10
12
|
@name = name
|
11
13
|
@condition = condition
|
12
14
|
@block = block
|
13
|
-
@resource = resource
|
14
|
-
|
15
|
-
end
|
15
|
+
@resource = resource
|
16
|
+
return if @resource
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
if @block
|
19
|
+
@resource = resource_class
|
20
|
+
elsif Alba.inferring
|
21
|
+
const_parent = nesting.nil? ? Object : Object.const_get(nesting)
|
22
|
+
@resource = const_parent.const_get("#{ActiveSupport::Inflector.classify(@name)}Resource")
|
23
|
+
else
|
24
|
+
raise ArgumentError, 'When Alba.inferring is false, either resource or block is required'
|
25
|
+
end
|
20
26
|
end
|
21
27
|
|
22
28
|
private
|
23
29
|
|
30
|
+
def constantize(resource)
|
31
|
+
case resource # rubocop:disable Style/MissingElse
|
32
|
+
when Class
|
33
|
+
resource
|
34
|
+
when Symbol, String
|
35
|
+
Object.const_get(resource)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
24
39
|
def resource_class
|
25
40
|
klass = Class.new
|
26
41
|
klass.include(Alba::Resource)
|
data/lib/alba/key_transformer.rb
CHANGED
@@ -16,6 +16,7 @@ module Alba
|
|
16
16
|
# @return [String] transformed key
|
17
17
|
# @raise [Alba::Error] when transform_type is not supported
|
18
18
|
def transform(key, transform_type)
|
19
|
+
key = key.to_s
|
19
20
|
case transform_type
|
20
21
|
when :camel
|
21
22
|
ActiveSupport::Inflector.camelize(key)
|
@@ -24,7 +25,7 @@ module Alba
|
|
24
25
|
when :dash
|
25
26
|
ActiveSupport::Inflector.dasherize(key)
|
26
27
|
else
|
27
|
-
raise ::Alba::Error, "Unknown transform_type: #{transform_type}. Supported transform_type are :camel and :dash."
|
28
|
+
raise ::Alba::Error, "Unknown transform_type: #{transform_type}. Supported transform_type are :camel, :lower_camel and :dash."
|
28
29
|
end
|
29
30
|
end
|
30
31
|
end
|
data/lib/alba/many.rb
CHANGED
@@ -6,12 +6,16 @@ module Alba
|
|
6
6
|
# Recursively converts objects into an Array of Hashes
|
7
7
|
#
|
8
8
|
# @param target [Object] the object having an association method
|
9
|
+
# @param within [Hash] determines what associations to be serialized. If not set, it serializes all associations.
|
9
10
|
# @param params [Hash] user-given Hash for arbitrary data
|
10
11
|
# @return [Array<Hash>]
|
11
|
-
def to_hash(target, params: {})
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
def to_hash(target, within: nil, params: {})
|
13
|
+
@object = target.public_send(@name)
|
14
|
+
@object = @condition.call(@object, params) if @condition
|
15
|
+
return if @object.nil?
|
16
|
+
|
17
|
+
@resource = constantize(@resource)
|
18
|
+
@object.map { |o| @resource.new(o, params: params, within: within).to_hash }
|
15
19
|
end
|
16
20
|
end
|
17
21
|
end
|
data/lib/alba/one.rb
CHANGED
@@ -6,12 +6,16 @@ module Alba
|
|
6
6
|
# Recursively converts an object into a Hash
|
7
7
|
#
|
8
8
|
# @param target [Object] the object having an association method
|
9
|
+
# @param within [Hash] determines what associations to be serialized. If not set, it serializes all associations.
|
9
10
|
# @param params [Hash] user-given Hash for arbitrary data
|
10
11
|
# @return [Hash]
|
11
|
-
def to_hash(target, params: {})
|
12
|
-
object = target.public_send(@name)
|
13
|
-
object = @condition.call(object, params) if @condition
|
14
|
-
@
|
12
|
+
def to_hash(target, within: nil, params: {})
|
13
|
+
@object = target.public_send(@name)
|
14
|
+
@object = @condition.call(object, params) if @condition
|
15
|
+
return if @object.nil?
|
16
|
+
|
17
|
+
@resource = constantize(@resource)
|
18
|
+
@resource.new(object, params: params, within: within).to_hash
|
15
19
|
end
|
16
20
|
end
|
17
21
|
end
|
data/lib/alba/resource.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require_relative 'serializer'
|
2
1
|
require_relative 'one'
|
3
2
|
require_relative 'many'
|
4
3
|
|
@@ -7,7 +6,7 @@ module Alba
|
|
7
6
|
module Resource
|
8
7
|
# @!parse include InstanceMethods
|
9
8
|
# @!parse extend ClassMethods
|
10
|
-
DSLS = {_attributes: {},
|
9
|
+
DSLS = {_attributes: {}, _key: nil, _transform_keys: nil, _transforming_root_key: false, _on_error: nil}.freeze
|
11
10
|
private_constant :DSLS
|
12
11
|
|
13
12
|
# @private
|
@@ -25,32 +24,26 @@ module Alba
|
|
25
24
|
|
26
25
|
# Instance methods
|
27
26
|
module InstanceMethods
|
28
|
-
attr_reader :object, :
|
27
|
+
attr_reader :object, :params
|
29
28
|
|
30
29
|
# @param object [Object] the object to be serialized
|
31
30
|
# @param params [Hash] user-given Hash for arbitrary data
|
32
|
-
|
31
|
+
# @param within [Hash] determines what associations to be serialized. If not set, it serializes all associations.
|
32
|
+
def initialize(object, params: {}, within: true)
|
33
33
|
@object = object
|
34
34
|
@params = params.freeze
|
35
|
+
@within = within
|
35
36
|
DSLS.each_key { |name| instance_variable_set("@#{name}", self.class.public_send(name)) }
|
36
37
|
end
|
37
38
|
|
38
|
-
#
|
39
|
+
# Serialize object into JSON string
|
39
40
|
#
|
40
|
-
# @param
|
41
|
+
# @param key [Symbol]
|
41
42
|
# @return [String] serialized JSON string
|
42
|
-
def serialize(
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
when ->(obj) { obj.is_a?(Class) && obj <= Alba::Serializer }
|
47
|
-
with
|
48
|
-
when Proc
|
49
|
-
inline_extended_serializer(with)
|
50
|
-
else
|
51
|
-
raise ArgumentError, 'Unexpected type for with, possible types are Class or Proc'
|
52
|
-
end
|
53
|
-
serializer.new(self).serialize
|
43
|
+
def serialize(key: nil)
|
44
|
+
key = key.nil? ? _key : key
|
45
|
+
hash = key && key != '' ? {key.to_s => serializable_hash} : serializable_hash
|
46
|
+
Alba.encoder.call(hash)
|
54
47
|
end
|
55
48
|
|
56
49
|
# A Hash for serialization
|
@@ -61,22 +54,67 @@ module Alba
|
|
61
54
|
end
|
62
55
|
alias to_hash serializable_hash
|
63
56
|
|
64
|
-
# @return [Symbol]
|
65
|
-
def key
|
66
|
-
@_key || self.class.name.delete_suffix('Resource').downcase.gsub(/:{2}/, '_').to_sym
|
67
|
-
end
|
68
|
-
|
69
57
|
private
|
70
58
|
|
71
|
-
#
|
59
|
+
# @return [String]
|
60
|
+
def _key
|
61
|
+
return @_key.to_s unless @_key == true && Alba.inferring
|
62
|
+
|
63
|
+
resource_name = self.class.name.demodulize.delete_suffix('Resource').underscore
|
64
|
+
key = collection? ? resource_name.pluralize : resource_name
|
65
|
+
transforming_root_key = @_transforming_root_key.nil? ? Alba.transforming_root_key : @_transforming_root_key
|
66
|
+
transforming_root_key ? transform_key(key) : key
|
67
|
+
end
|
68
|
+
|
72
69
|
def converter
|
73
|
-
lambda do |
|
74
|
-
@_attributes.map do |key, attribute|
|
75
|
-
|
76
|
-
|
70
|
+
lambda do |object|
|
71
|
+
arrays = @_attributes.map do |key, attribute|
|
72
|
+
key = transform_key(key)
|
73
|
+
if attribute.is_a?(Array) # Conditional
|
74
|
+
conditional_attribute(object, key, attribute)
|
75
|
+
else
|
76
|
+
[key, fetch_attribute(object, attribute)]
|
77
|
+
end
|
78
|
+
rescue ::Alba::Error, FrozenError, TypeError
|
79
|
+
raise
|
80
|
+
rescue StandardError => e
|
81
|
+
handle_error(e, object, key, attribute)
|
82
|
+
end
|
83
|
+
arrays.reject(&:empty?).to_h
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def conditional_attribute(object, key, attribute)
|
88
|
+
condition = attribute.last
|
89
|
+
arity = condition.arity
|
90
|
+
return [] if arity <= 1 && !condition.call(object)
|
91
|
+
|
92
|
+
fetched_attribute = fetch_attribute(object, attribute.first)
|
93
|
+
attr = if attribute.first.is_a?(Alba::Association)
|
94
|
+
attribute.first.object
|
95
|
+
else
|
96
|
+
fetched_attribute
|
97
|
+
end
|
98
|
+
return [] if arity >= 2 && !condition.call(object, attr)
|
99
|
+
|
100
|
+
[key, fetched_attribute]
|
101
|
+
end
|
102
|
+
|
103
|
+
def handle_error(error, object, key, attribute)
|
104
|
+
on_error = @_on_error || Alba._on_error
|
105
|
+
case on_error
|
106
|
+
when :raise, nil
|
107
|
+
raise
|
108
|
+
when :nullify
|
109
|
+
[key, nil]
|
110
|
+
when :ignore
|
111
|
+
[]
|
112
|
+
when Proc
|
113
|
+
on_error.call(error, object, key, attribute, self.class)
|
114
|
+
else
|
115
|
+
raise ::Alba::Error, "Unknown on_error: #{on_error.inspect}"
|
77
116
|
end
|
78
117
|
end
|
79
|
-
# rubocop:enable Style/MethodCalledOnDoEndBlock
|
80
118
|
|
81
119
|
# Override this method to supply custom key transform method
|
82
120
|
def transform_key(key)
|
@@ -86,29 +124,81 @@ module Alba
|
|
86
124
|
KeyTransformer.transform(key, @_transform_keys)
|
87
125
|
end
|
88
126
|
|
89
|
-
def fetch_attribute(
|
127
|
+
def fetch_attribute(object, attribute)
|
90
128
|
case attribute
|
91
129
|
when Symbol
|
92
|
-
|
130
|
+
object.public_send attribute
|
93
131
|
when Proc
|
94
|
-
instance_exec(
|
132
|
+
instance_exec(object, &attribute)
|
95
133
|
when Alba::One, Alba::Many
|
96
|
-
|
134
|
+
within = check_within
|
135
|
+
return unless within
|
136
|
+
|
137
|
+
attribute.to_hash(object, params: params, within: within)
|
138
|
+
when Hash # Typed Attribute
|
139
|
+
typed_attribute(object, attribute)
|
97
140
|
else
|
98
141
|
raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
|
99
142
|
end
|
100
143
|
end
|
101
144
|
|
102
|
-
def
|
103
|
-
|
104
|
-
|
105
|
-
|
145
|
+
def typed_attribute(object, hash)
|
146
|
+
attr_name = hash[:attr_name]
|
147
|
+
type = hash[:type]
|
148
|
+
type_converter = hash[:type_converter]
|
149
|
+
value, result = type_check(object, attr_name, type)
|
150
|
+
return value if result
|
151
|
+
raise TypeError if !result && !type_converter
|
152
|
+
|
153
|
+
type_converter = type_converter_for(type) if type_converter == true
|
154
|
+
type_converter.call(value)
|
155
|
+
rescue TypeError
|
156
|
+
raise TypeError, "Attribute #{attr_name} is expected to be #{type} but actually #{value.nil? ? 'nil' : value.class.name}."
|
157
|
+
end
|
158
|
+
|
159
|
+
def type_check(object, attr_name, type)
|
160
|
+
value = object.public_send(attr_name)
|
161
|
+
type_correct = case type
|
162
|
+
when :String, ->(klass) { klass == String }
|
163
|
+
value.is_a?(String)
|
164
|
+
when :Integer, ->(klass) { klass == Integer }
|
165
|
+
value.is_a?(Integer)
|
166
|
+
when :Boolean
|
167
|
+
[true, false].include?(attr_name)
|
168
|
+
else
|
169
|
+
raise Alba::UnsupportedType, "Unknown type: #{type}"
|
170
|
+
end
|
171
|
+
[value, type_correct]
|
106
172
|
end
|
107
173
|
|
108
|
-
def
|
109
|
-
|
110
|
-
klass
|
111
|
-
|
174
|
+
def type_converter_for(type)
|
175
|
+
case type
|
176
|
+
when :String, ->(klass) { klass == String }
|
177
|
+
->(object) { object.to_s }
|
178
|
+
when :Integer, ->(klass) { klass == Integer }
|
179
|
+
->(object) { Integer(object) }
|
180
|
+
when :Boolean
|
181
|
+
->(object) { !!object }
|
182
|
+
else
|
183
|
+
raise Alba::UnsupportedType, "Unknown type: #{type}"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def check_within
|
188
|
+
case @within
|
189
|
+
when Hash # Traverse within tree
|
190
|
+
@within.fetch(_key.to_sym, nil)
|
191
|
+
when Array # within tree ends with Array
|
192
|
+
@within.find { |item| item.to_sym == _key.to_sym } # Check if at least one item in the array matches current resource
|
193
|
+
when Symbol # within tree could end with Symbol
|
194
|
+
@within == _key.to_sym # Check if the symbol matches current resource
|
195
|
+
when true # In this case, Alba serializes all associations.
|
196
|
+
true
|
197
|
+
when nil, false # In these cases, Alba stops serialization here.
|
198
|
+
false
|
199
|
+
else
|
200
|
+
raise Alba::Error, "Unknown type for within option: #{@within.class}"
|
201
|
+
end
|
112
202
|
end
|
113
203
|
|
114
204
|
def collection?
|
@@ -129,19 +219,32 @@ module Alba
|
|
129
219
|
# Set multiple attributes at once
|
130
220
|
#
|
131
221
|
# @param attrs [Array<String, Symbol>]
|
132
|
-
|
133
|
-
|
222
|
+
# @param options [Hash] option hash including `if` that is a condition to render these attributes
|
223
|
+
def attributes(*attrs, if: nil, **attrs_with_types) # rubocop:disable Naming/MethodParameterName
|
224
|
+
if_value = binding.local_variable_get(:if)
|
225
|
+
attrs.each do |attr_name|
|
226
|
+
attr = if_value ? [attr_name.to_sym, if_value] : attr_name.to_sym
|
227
|
+
@_attributes[attr_name.to_sym] = attr
|
228
|
+
end
|
229
|
+
attrs_with_types.each do |attr_name, type_and_converter|
|
230
|
+
attr_name = attr_name.to_sym
|
231
|
+
type, type_converter = type_and_converter
|
232
|
+
typed_attr = {attr_name: attr_name, type: type, type_converter: type_converter}
|
233
|
+
attr = if_value ? [typed_attr, if_value] : typed_attr
|
234
|
+
@_attributes[attr_name] = attr
|
235
|
+
end
|
134
236
|
end
|
135
237
|
|
136
238
|
# Set an attribute with the given block
|
137
239
|
#
|
138
240
|
# @param name [String, Symbol] key name
|
241
|
+
# @param options [Hash] option hash including `if` that is a condition to render
|
139
242
|
# @param block [Block] the block called during serialization
|
140
243
|
# @raise [ArgumentError] if block is absent
|
141
|
-
def attribute(name, &block)
|
244
|
+
def attribute(name, **options, &block)
|
142
245
|
raise ArgumentError, 'No block given in attribute method' unless block
|
143
246
|
|
144
|
-
@_attributes[name.to_sym] = block
|
247
|
+
@_attributes[name.to_sym] = options[:if] ? [block, options[:if]] : block
|
145
248
|
end
|
146
249
|
|
147
250
|
# Set One association
|
@@ -150,10 +253,13 @@ module Alba
|
|
150
253
|
# @param condition [Proc]
|
151
254
|
# @param resource [Class<Alba::Resource>]
|
152
255
|
# @param key [String, Symbol] used as key when given
|
256
|
+
# @param options [Hash] option hash including `if` that is a condition to render
|
153
257
|
# @param block [Block]
|
154
258
|
# @see Alba::One#initialize
|
155
|
-
def one(name, condition = nil, resource: nil, key: nil, &block)
|
156
|
-
|
259
|
+
def one(name, condition = nil, resource: nil, key: nil, **options, &block)
|
260
|
+
nesting = self.name&.rpartition('::')&.first
|
261
|
+
one = One.new(name: name, condition: condition, resource: resource, nesting: nesting, &block)
|
262
|
+
@_attributes[key&.to_sym || name.to_sym] = options[:if] ? [one, options[:if]] : one
|
157
263
|
end
|
158
264
|
alias has_one one
|
159
265
|
|
@@ -163,25 +269,27 @@ module Alba
|
|
163
269
|
# @param condition [Proc]
|
164
270
|
# @param resource [Class<Alba::Resource>]
|
165
271
|
# @param key [String, Symbol] used as key when given
|
272
|
+
# @param options [Hash] option hash including `if` that is a condition to render
|
166
273
|
# @param block [Block]
|
167
274
|
# @see Alba::Many#initialize
|
168
|
-
def many(name, condition = nil, resource: nil, key: nil, &block)
|
169
|
-
|
275
|
+
def many(name, condition = nil, resource: nil, key: nil, **options, &block)
|
276
|
+
nesting = self.name&.rpartition('::')&.first
|
277
|
+
many = Many.new(name: name, condition: condition, resource: resource, nesting: nesting, &block)
|
278
|
+
@_attributes[key&.to_sym || name.to_sym] = options[:if] ? [many, options[:if]] : many
|
170
279
|
end
|
171
280
|
alias has_many many
|
172
281
|
|
173
|
-
# Set serializer for the resource
|
174
|
-
#
|
175
|
-
# @param name [Alba::Serializer]
|
176
|
-
def serializer(name)
|
177
|
-
@_serializer = name <= Alba::Serializer ? name : nil
|
178
|
-
end
|
179
|
-
|
180
282
|
# Set key
|
181
283
|
#
|
182
284
|
# @param key [String, Symbol]
|
183
285
|
def key(key)
|
184
|
-
@_key = key.to_sym
|
286
|
+
@_key = key.respond_to?(:to_sym) ? key.to_sym : key
|
287
|
+
end
|
288
|
+
|
289
|
+
# Set key to true
|
290
|
+
#
|
291
|
+
def key!
|
292
|
+
@_key = true
|
185
293
|
end
|
186
294
|
|
187
295
|
# Delete attributes
|
@@ -196,9 +304,22 @@ module Alba
|
|
196
304
|
|
197
305
|
# Transform keys as specified type
|
198
306
|
#
|
199
|
-
# @
|
200
|
-
|
307
|
+
# @param type [String, Symbol]
|
308
|
+
# @param root [Boolean] decides if root key also should be transformed
|
309
|
+
def transform_keys(type, root: nil)
|
201
310
|
@_transform_keys = type.to_sym
|
311
|
+
@_transforming_root_key = root
|
312
|
+
end
|
313
|
+
|
314
|
+
# Set error handler
|
315
|
+
#
|
316
|
+
# @param [Symbol] handler
|
317
|
+
# @param [Block]
|
318
|
+
def on_error(handler = nil, &block)
|
319
|
+
raise ArgumentError, 'You cannot specify error handler with both Symbol and block' if handler && block
|
320
|
+
raise ArgumentError, 'You must specify error handler with either Symbol or block' unless handler || block
|
321
|
+
|
322
|
+
@_on_error = handler || block
|
202
323
|
end
|
203
324
|
end
|
204
325
|
end
|