alba 3.8.0 → 3.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ff1f7d9c2cf5b49ee88a9cf864e3a66251ccdb502515a1ea91c64837f84d22d
4
- data.tar.gz: d26b6be0d948d848ba35f216392f9bafe3581925816cc9ee9eeaf651a3face3b
3
+ metadata.gz: 9f883beafbee55bdfc1bb9b55e821c6df5b167e5311cbeced743ae7c60de5657
4
+ data.tar.gz: e9c031cd63e51f160f1ec1f1b42ac8676b0ff172ff2438f549ab83d38d848817
5
5
  SHA512:
6
- metadata.gz: b4b114df3e7e26bf2249f6f683efd1c856594cea376d6b8e33078f1cb9e3810132cf4cb120cfbc6682a556f84ca40115e157f09376c8a81af0160e20efcb2e23
7
- data.tar.gz: 314f599a9564c053ed653178dd743291cb9125965e8bef7146bed5c049ec44568a40bb1b201df700fe0025e344ae4586af769a377db4f2a50527875aaf2c2c04
6
+ metadata.gz: 73b22da7dc5d360297838b326c3f130e18027b9fc203e3bdec48c13f80f4105a5fa019304a947dbc85aea40ee94e796cb20ba4c7c51f9a8c3cc02d29336f80f9
7
+ data.tar.gz: 2d82dfd6188126db9726982440465e9bc4cf6165e2eaf2c51f0d729eee1e8fa2d2c54b5d8aafce710979ba67be437f4bc152dc1e91352cea421925b32068c73f
data/CHANGELOG.md CHANGED
@@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## 3.9.0 2025-08-14
10
+
11
+ ### Added
12
+
13
+ - Add source option to associations [#459](https://github.com/okuramasafumi/alba/pull/459)
14
+ - Thank you, @skryukov
15
+
16
+ ### Fixed
17
+
18
+ - `params` isn't available in `attribute` with two-arity condition [#456](https://github.com/okuramasafumi/alba/issues/456)
19
+
9
20
  ## 3.8.0 2025-08-02
10
21
 
11
22
  ### Added
data/README.md CHANGED
@@ -617,6 +617,34 @@ FooResource.new(foo, params: {expose_secret: true}).serialize # => '{"foo":{"bar
617
617
  FooResourceWithParamsOverride.new(foo, params: {expose_secret: true}).serialize # => '{"foo":{"bar":{"baz":{"data":1}}}}'
618
618
  ```
619
619
 
620
+ #### Custom association source
621
+
622
+ You can specify a custom source for associations using the `source` option with a proc. The `source` proc is executed in the context of the target object and can receive `params` for dynamic behavior. This allows you to retrieve association data from methods other than the association name or access instance variables.
623
+
624
+ ```ruby
625
+ class User
626
+ attr_accessor :id, :name, :metadata
627
+
628
+ def custom_profile
629
+ {profile: {email: "#{name.downcase}@example.com"}}
630
+ end
631
+ end
632
+
633
+ class UserResource
634
+ include Alba::Resource
635
+
636
+ attributes :id, :name
637
+
638
+ # Use a custom method as source
639
+ one :profile, source: proc { custom_profile[:profile] }
640
+
641
+ # Access instance variables
642
+ one :user_metadata, source: proc { @metadata }
643
+ end
644
+ ```
645
+
646
+
647
+
620
648
  ### Nested Attribute
621
649
 
622
650
  Alba supports nested attributes that makes it easy to build complex data structure from single object.
@@ -778,15 +806,15 @@ Alba.serialize(
778
806
  [foo1, bar1, foo2, bar2],
779
807
  # `with` option takes a lambda to return resource class
780
808
  with: lambda do |obj|
781
- case obj
782
- when Foo
783
- CustomFooResource
784
- when Bar
785
- BarResource
786
- else
787
- raise # Impossible in this case
788
- end
789
- end
809
+ case obj
810
+ when Foo
811
+ CustomFooResource
812
+ when Bar
813
+ BarResource
814
+ else
815
+ raise # Impossible in this case
816
+ end
817
+ end
790
818
  )
791
819
  # => '[{"id":1},{"id":1,"address":"bar1"},{"id":2},{"id":2,"address":"bar2"}]'
792
820
  # Note `CustomFooResource` is used here
@@ -1225,7 +1253,7 @@ There are four possible arguments `on_error` method accepts.
1225
1253
  * `:nullify` sets the attribute with the error to `nil`.
1226
1254
  * Block gives you more control over what to be returned.
1227
1255
 
1228
- The block receives five arguments, `error`, `object`, `key`, `attribute` and `resource class` and must return a two-element array. Below is an example.
1256
+ The block receives five arguments, `error`, `object`, `key`, `attribute` and `resource class` and must return a two-element array. You can also ignore the given key with returning `Alba::REMOVE_KEY`, so that you can get even finer control over errors. Below is an example.
1229
1257
 
1230
1258
  ```ruby
1231
1259
  class ExampleResource
@@ -1235,12 +1263,14 @@ class ExampleResource
1235
1263
  if resource_class == MyResource
1236
1264
  ['error_fallback', object.error_fallback]
1237
1265
  else
1238
- [key, error.message]
1266
+ Alba::REMOVE_KEY
1239
1267
  end
1240
1268
  end
1241
1269
  end
1242
1270
  ```
1243
1271
 
1272
+ For more information, consult to [test code](https://github.com/okuramasafumi/alba/blob/main/test/usecases/on_error_test.rb).
1273
+
1244
1274
  ### Nil handling
1245
1275
 
1246
1276
  Sometimes we want to convert `nil` to different values such as empty string. Alba provides a flexible way to handle `nil`.
@@ -1520,8 +1550,8 @@ Alba supports serializing JSON in a layout. You need a file for layout and then
1520
1550
 
1521
1551
  ```erb
1522
1552
  {
1523
- "header": "my_header",
1524
- "body": <%= serialized_json %>
1553
+ "header": "my_header",
1554
+ "body": <%= serialized_json %>
1525
1555
  }
1526
1556
  ```
1527
1557
 
@@ -1909,7 +1939,7 @@ AuthorResource.new(
1909
1939
  author,
1910
1940
  params: {
1911
1941
  index: author.books.map.with_index { |book, index| [book.id, index] }
1912
- .to_h
1942
+ .to_h
1913
1943
  }
1914
1944
  ).serialize
1915
1945
  # => {"id":2,"books":[{"id":2,"name":"book2","index":0},{"id":3,"name":"book3","index":1},{"id":1,"name":"book1","index":2}]}
@@ -16,16 +16,29 @@ module Alba
16
16
  # @param condition [Proc, nil] a proc filtering data
17
17
  # @param resource [Class<Alba::Resource>, Proc, String, Symbol, nil]
18
18
  # a resource class for the association, a proc returning a resource class or a name of the resource
19
+ # @param source [Proc, nil] a proc to specify the source of the association
19
20
  # @param with_traits [Symbol, Array<Symbol>, nil] specified traits
20
21
  # @param params [Hash] params override for the association
21
22
  # @param nesting [String] a namespace where source class is inferred with
22
23
  # @param key_transformation [Symbol] key transformation type
23
24
  # @param helper [Module] helper module to include
24
25
  # @param block [Block] used to define resource when resource arg is absent
25
- def initialize(name:, condition: nil, resource: nil, with_traits: nil, params: {}, nesting: nil, key_transformation: :none, helper: nil, &block)
26
+ def initialize(
27
+ name:,
28
+ condition: nil,
29
+ resource: nil,
30
+ source: nil,
31
+ with_traits: nil,
32
+ params: {},
33
+ nesting: nil,
34
+ key_transformation: :none,
35
+ helper: nil,
36
+ &block
37
+ )
26
38
  @name = name
27
39
  @condition = condition
28
40
  @resource = resource
41
+ @source = source
29
42
  @with_traits = with_traits
30
43
  @params = params
31
44
  return if @resource
@@ -64,7 +77,11 @@ module Alba
64
77
  private
65
78
 
66
79
  def object_from(target, params)
67
- o = target.is_a?(Hash) ? target.fetch(@name) : target.__send__(@name)
80
+ o = if @source
81
+ target.instance_exec(params, &@source)
82
+ else
83
+ target.is_a?(Hash) ? target.fetch(@name) : target.__send__(@name)
84
+ end
68
85
  o = @condition.call(o, params, target) if @condition
69
86
  o
70
87
  end
@@ -25,7 +25,7 @@ module Alba
25
25
  fetched_attribute = yield(@body)
26
26
  return fetched_attribute unless with_two_arity_proc_condition?
27
27
 
28
- return Alba::REMOVE_KEY unless resource.instance_exec(object, second_object(object), &@condition)
28
+ return Alba::REMOVE_KEY unless resource.instance_exec(object, second_object(object, resource), &@condition)
29
29
 
30
30
  fetched_attribute
31
31
  end
@@ -50,14 +50,14 @@ module Alba
50
50
  @condition.is_a?(Proc) && @condition.arity >= 2
51
51
  end
52
52
 
53
- def second_object(object)
53
+ def second_object(object, resource)
54
54
  case @body
55
55
  when Symbol, Alba::Association, Alba::TypedAttribute
56
56
  object.__send__(@body.name)
57
57
  when Alba::NestedAttribute
58
58
  nil
59
59
  when Proc
60
- @body.call(object)
60
+ resource.instance_exec(object, &@body)
61
61
  else raise Alba::Error, "Unreachable code, @body is: #{@body.inspect}"
62
62
  end
63
63
  end
data/lib/alba/resource.rb CHANGED
@@ -429,6 +429,7 @@ module Alba
429
429
  # @param condition [Proc, nil] a Proc to modify the association
430
430
  # @param resource [Class<Alba::Resource>, String, Proc, nil] representing resource for this association
431
431
  # @param serializer [Class<Alba::Resource>, String, Proc, nil] alias for `resource`
432
+ # @param source [Proc, nil] a Proc to customize the association source
432
433
  # @param key [String, Symbol, nil] used as key when given
433
434
  # @param with_traits [Symbol, Array<Symbol>, nil] specified traits
434
435
  # @param params [Hash] params override for the association
@@ -437,11 +438,11 @@ module Alba
437
438
  # @param block [Block]
438
439
  # @return [void]
439
440
  # @see Alba::Association#initialize
440
- def association(name, condition = nil, resource: nil, serializer: nil, key: nil, with_traits: nil, params: {}, **options, &block)
441
+ def association(name, condition = nil, resource: nil, serializer: nil, source: nil, key: nil, with_traits: nil, params: {}, **options, &block)
441
442
  resource ||= serializer
442
443
  transformation = @_key_transformation_cascade ? @_transform_type : :none
443
444
  assoc = Association.new(
444
- name: name, condition: condition, resource: resource, with_traits: with_traits,
445
+ name: name, condition: condition, resource: resource, source: source, with_traits: with_traits,
445
446
  params: params, nesting: nesting, key_transformation: transformation, helper: @_helper,
446
447
  &block
447
448
  )
data/lib/alba/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alba
4
- VERSION = '3.8.0'
4
+ VERSION = '3.9.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alba
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.8.0
4
+ version: 3.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OKURA Masafumi