alba 3.6.0 → 3.7.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: 9013289126b33b20a7460d7c5092a3df8a39c7d79c7114d6f33e7111a2703a20
4
- data.tar.gz: ae73ef30b48cdc1dfee93cd5c7cb55576ec0bd818d899c0fc2a041fbe09a90f7
3
+ metadata.gz: 14523f0f31f5993205b02095c3e6a8115ef83728961cf720dde4d9599be3168a
4
+ data.tar.gz: 9a2de9344c9b7bf95daa07e0d61339a08285f0cdadf9b694b58f73e7b0773970
5
5
  SHA512:
6
- metadata.gz: ed86e0c309632cb9fe70752f5c7d5ddacbd529ea5c8b06ec802736e2fd745604470cf3163b43d287a6409529babf0d6c4d713c0d7b6035d4248ea33eec8e3a49
7
- data.tar.gz: 93fc142fabd4a9358f279dccd0a85c8d0a22cabb8ff452d76ef221bb7ca929aa28bbd58a20bb29bc4a0bbe955e64a2616adf2f882728540e349eef3f82418906
6
+ metadata.gz: e7f8062cca1bbccbe4d4e871fd5ad2ab42a5b25acc0d2b9edd3e8247af021edaca981988eeb8428675c8bdc8bcbc14fa5ee45d90d524ca76987ab469fc2a6203
7
+ data.tar.gz: ea0cd1598c2ef8f76e740309ff925b8c26ef60bef6174755b23549d3fd9a98aefeab26bb6d47b73c92c9b92d84125717b157369f25ba2d3631532bec522a9765
data/CHANGELOG.md CHANGED
@@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.7.0] 2025-05-08
10
+
11
+ ### Added
12
+
13
+ - Traits [#434](https://github.com/okuramasafumi/alba/pull/434)
14
+
9
15
  ## [3.6.0] 2025-03-11
10
16
 
11
17
  ### Added
data/README.md CHANGED
@@ -122,7 +122,7 @@ Alba supports CRuby 3.0 and higher and latest JRuby and TruffleRuby.
122
122
 
123
123
  ## Documentation
124
124
 
125
- You can find the documentation on [RubyDoc](https://rubydoc.info/github/okuramasafumi/alba).
125
+ You can find the documentation on [GitHub Pages](https://okuramasafumi.github.io/alba/).
126
126
 
127
127
  ## Features
128
128
 
@@ -1073,6 +1073,40 @@ class UserResource2
1073
1073
  end
1074
1074
  ```
1075
1075
 
1076
+ ### Traits
1077
+
1078
+ Traits is an easy way to a group of attributes and apply it to the resource.
1079
+
1080
+ ```ruby
1081
+ class User
1082
+ attr_accessor :id, :name, :email
1083
+
1084
+ def initialize(id, name, email)
1085
+ @id = id
1086
+ @name = name
1087
+ @email = email
1088
+ end
1089
+ end
1090
+
1091
+ class UserResource
1092
+ include Alba::Resource
1093
+
1094
+ attributes :id
1095
+
1096
+ trait :additional do
1097
+ attributes :name, :email
1098
+ end
1099
+ end
1100
+
1101
+ user = User.new(1, 'Foo', 'foo@example.org')
1102
+ UserResource.new(user).serialize # => '{"id":1}'
1103
+ UserResource.new(user, with_traits: :additional).serialize # => '{"id":1,"name":"Foo","email":"foo@example.com"}'
1104
+ ```
1105
+
1106
+ This way, we can keep the resource class simple and inject conditions from outside. We can get the same result with the combination of `if` and `params`, but using `traits` DSL can make the resource class readable.
1107
+
1108
+ We can specify multiple traits at once with `with_traits: []` keyword argument.
1109
+
1076
1110
  ### Default
1077
1111
 
1078
1112
  Alba doesn't support default value for attributes, but it's easy to set a default value.
@@ -1807,6 +1841,58 @@ Here, we override `serialize` method with `prepend`. In overridden method we pri
1807
1841
 
1808
1842
  Don't forget calling `super` in this way.
1809
1843
 
1844
+ ## Tips and Tricks
1845
+
1846
+ ### Treating specific classes as non-collection
1847
+
1848
+ Sometimes we need to serialize an object that's `Enumerable` but not a collection. By default, Alba treats `Hash`, `Range` and `Struct` as non-collection object, but if we want to add some classes to this list, we can override `Alba.collection?` method like following:
1849
+
1850
+ ```ruby
1851
+ Alba.singleton_class.prepend(
1852
+ Module.new do
1853
+ def collection?(object)
1854
+ super && !object.is_a?(SomeClass)
1855
+ end
1856
+ end
1857
+ )
1858
+ ```
1859
+
1860
+ ### Adding indexes to `many` association
1861
+
1862
+ Let's say an author has many books. We want returned JSON to include indexes of each book. In this case, we can reduce the number of executed SQL by fetching indexes ahead and push indexes into `param`.
1863
+
1864
+ ```ruby
1865
+ Author = Data.define(:id, :books)
1866
+ Book = Data.define(:id, :name)
1867
+
1868
+ book1 = Book.new(1, 'book1')
1869
+ book2 = Book.new(2, 'book2')
1870
+ book3 = Book.new(3, 'book3')
1871
+
1872
+ author = Author.new(2, [book2, book3, book1])
1873
+
1874
+ class AuthorResource
1875
+ include Alba::Resource
1876
+
1877
+ attributes :id
1878
+ many :books do
1879
+ attributes :id, :name
1880
+ attribute :index do |bar|
1881
+ params[:index][bar.id]
1882
+ end
1883
+ end
1884
+ end
1885
+
1886
+ AuthorResource.new(
1887
+ author,
1888
+ params: {
1889
+ index: author.books.map.with_index { |book, index| [book.id, index] }
1890
+ .to_h
1891
+ }
1892
+ ).serialize
1893
+ # => {"id":2,"books":[{"id":2,"name":"book2","index":0},{"id":3,"name":"book3","index":1},{"id":1,"name":"book1","index":2}]}
1894
+ ```
1895
+
1810
1896
  ## Rails
1811
1897
 
1812
1898
  When you use Alba in Rails, you can create an initializer file with the line below for compatibility with Rails JSON encoder.
@@ -1840,6 +1926,10 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
1840
1926
 
1841
1927
  Thank you for begin interested in contributing to Alba! Please see [contributors guide](https://github.com/okuramasafumi/alba/blob/main/CONTRIBUTING.md) before start contributing. If you have any questions, please feel free to ask in [Discussions](https://github.com/okuramasafumi/alba/discussions).
1842
1928
 
1929
+ ## Versioning
1930
+
1931
+ Alba follows [Semver 2.0.0](https://semver.org/spec/v2.0.0.html).
1932
+
1843
1933
  ## License
1844
1934
 
1845
1935
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/lib/alba/resource.rb CHANGED
@@ -14,7 +14,7 @@ module Alba
14
14
  module Resource
15
15
  # @!parse include InstanceMethods
16
16
  # @!parse extend ClassMethods
17
- INTERNAL_VARIABLES = {_attributes: {}, _key: nil, _key_for_collection: nil, _meta: nil, _transform_type: :none, _transforming_root_key: false, _key_transformation_cascade: true, _on_error: nil, _on_nil: nil, _layout: nil, _collection_key: nil, _helper: nil, _resource_methods: [], _select_arity: nil}.freeze # rubocop:disable Layout/LineLength
17
+ INTERNAL_VARIABLES = {_attributes: {}, _key: nil, _key_for_collection: nil, _meta: nil, _transform_type: :none, _transforming_root_key: false, _key_transformation_cascade: true, _on_error: nil, _on_nil: nil, _layout: nil, _collection_key: nil, _helper: nil, _resource_methods: [], _select_arity: nil, _traits: {}}.freeze # rubocop:disable Layout/LineLength
18
18
  private_constant :INTERNAL_VARIABLES
19
19
 
20
20
  WITHIN_DEFAULT = Object.new.freeze
@@ -46,10 +46,12 @@ module Alba
46
46
  # @param object [Object] the object to be serialized
47
47
  # @param params [Hash] user-given Hash for arbitrary data
48
48
  # @param within [Object, nil, false, true] determines what associations to be serialized. If not set, it serializes all associations.
49
- def initialize(object, params: {}, within: WITHIN_DEFAULT)
49
+ # @param with_traits [Symbol, Array<Symbol>, nil] specified traits
50
+ def initialize(object, params: {}, within: WITHIN_DEFAULT, with_traits: nil)
50
51
  @object = object
51
52
  @params = params
52
53
  @within = within
54
+ @with_traits = with_traits
53
55
  _setup
54
56
  end
55
57
 
@@ -106,6 +108,20 @@ module Alba
106
108
 
107
109
  private
108
110
 
111
+ def hash_from_traits(obj)
112
+ h = {}
113
+ return h if @with_traits.nil?
114
+
115
+ Array(@with_traits).each do |trait|
116
+ body = @_traits.fetch(trait) { raise Alba::Error, "Trait not found: #{trait}" }
117
+
118
+ resource_class = Alba.resource_class
119
+ resource_class.class_eval(&body)
120
+ h.merge!(resource_class.new(obj, params: params, within: @within).serializable_hash)
121
+ end
122
+ h
123
+ end
124
+
109
125
  def deprecated_serializable_hash
110
126
  Alba.collection?(@object) ? serializable_hash_for_collection : converter.call(@object)
111
127
  end
@@ -212,7 +228,7 @@ module Alba
212
228
  rescue StandardError => e
213
229
  handle_error(e, obj, key, attribute, hash)
214
230
  end
215
- hash
231
+ @with_traits.nil? ? hash : hash.merge!(hash_from_traits(obj))
216
232
  end
217
233
 
218
234
  # This is default behavior for getting attributes for serialization
@@ -455,6 +471,19 @@ module Alba
455
471
  end
456
472
  alias nested nested_attribute
457
473
 
474
+ # Set a trait
475
+ #
476
+ # @param name [String, Symbol] name of the trait
477
+ # @param block [Block] the "content" of the trait
478
+ # @raise [ArgumentError] if block is absent
479
+ # @return [void]
480
+ def trait(name, &block)
481
+ raise ArgumentError, 'No block given in trait method' unless block
482
+
483
+ name = name.to_sym
484
+ @_traits[name] = block
485
+ end
486
+
458
487
  # Set root key
459
488
  #
460
489
  # @param key [String, Symbol]
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.6.0'
4
+ VERSION = '3.7.0'
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alba
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.0
4
+ version: 3.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OKURA Masafumi
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-01 00:00:00.000000000 Z
10
+ date: 2025-05-08 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: Alba is the fastest JSON serializer for Ruby. It focuses on performance,
13
13
  flexibility and usability.
@@ -40,7 +40,7 @@ licenses:
40
40
  metadata:
41
41
  bug_tracker_uri: https://github.com/okuramasafumi/alba/issues
42
42
  changelog_uri: https://github.com/okuramasafumi/alba/blob/main/CHANGELOG.md
43
- documentation_uri: https://rubydoc.info/github/okuramasafumi/alba
43
+ documentation_uri: https://okuramasafumi.github.io/alba/
44
44
  source_code_uri: https://github.com/okuramasafumi/alba
45
45
  rubygems_mfa_required: 'true'
46
46
  rdoc_options: []