alba 0.10.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e8427c3365aa48ba76f97799757e5e32ae2f746d3b63c67d58e7c7ddadd17bae
4
- data.tar.gz: c995206962d4a041032b76113a2f053e48f50f787af12c491437ff98c55d4d2e
3
+ metadata.gz: f4a5b866825838f457bb17c0c1037f68c3e88a9b96c86dd9e0c456d101f69158
4
+ data.tar.gz: d1f451fff558385b3ae4610355a3abb9aced052ce138eff9913169a12c8a23c6
5
5
  SHA512:
6
- metadata.gz: b513dea8cfa68bf09e76114c3d6e14bd77a381f94ad9342c8692034069240c114b9eac95bf071662905de14efe269ac606a7cb2b50ec4107fa393391ed5ddf9d
7
- data.tar.gz: e44bc0f25be1342ea9424c3919c62cd40b1917eac62f6bf612cd7979ead6db5521200eae4d7ef9a795ee373145c4fb5c846886bc1869916fd744596ac57aecbc
6
+ metadata.gz: 71fdab1911c6fc9e1ba88e8cbdc553311b99aecd975462b05958e5be1e491aa10734b6b6f6f15f24ae98c8ab5a1b1021d6c544a172befcedd23ca80283529e98
7
+ data.tar.gz: 05f06f2e7f3ec93e0a616bec6e3d71a90590b68c7ce397050bb9c019d2bbf206b070ed1cf44603cd301fa5dd2634df50c4e08b75a8c478b2f0063b6551b5bdcc
@@ -6,6 +6,7 @@ inherit_gem:
6
6
  require:
7
7
  - rubocop-minitest
8
8
  - rubocop-performance
9
+ - rubocop-rake
9
10
 
10
11
  AllCops:
11
12
  Exclude:
@@ -18,9 +19,6 @@ AllCops:
18
19
  Bundler/GemComment:
19
20
  Enabled: false
20
21
 
21
- Layout/ClassStructure:
22
- Enabled: true
23
-
24
22
  Layout/SpaceInsideHashLiteralBraces:
25
23
  EnforcedStyle: no_space
26
24
 
@@ -38,12 +36,14 @@ Metrics/MethodLength:
38
36
  Max: 15
39
37
 
40
38
  Style/ConstantVisibility:
41
- Enabled: false
39
+ Exclude:
40
+ - 'lib/alba/version.rb'
42
41
 
43
42
  Style/Copyright:
44
43
  Enabled: false
45
44
 
46
- Style/DocumentationMethod:
45
+ # I know what I do :)
46
+ Style/DisableCopsWithinSourceCodeDirective:
47
47
  Enabled: false
48
48
 
49
49
  Style/FrozenStringLiteralComment:
@@ -5,5 +5,6 @@ rvm:
5
5
  - 2.5.8
6
6
  - 2.6.6
7
7
  - 2.7.1
8
+ # - ruby-head # oj doesn't work with Ruby 2.8.0
8
9
  - truffleruby
9
10
  before_install: gem install bundler -v 2.1.4
@@ -0,0 +1,2 @@
1
+ --no-private
2
+ --exclude lib/alba/version.rb
data/Gemfile CHANGED
@@ -5,10 +5,12 @@ gemspec
5
5
 
6
6
  gem 'activesupport', require: false # For backend
7
7
  gem 'coveralls', require: false # For test coverage
8
- gem 'minitest', '~> 5.0' # For test
9
- gem 'oj', '~> 3.10', platforms: :ruby # For backend
8
+ gem 'minitest', '~> 5.14' # For test
9
+ gem 'oj', '~> 3.11', platform: :ruby, require: false # For backend
10
10
  gem 'rake', '~> 13.0' # For test and automation
11
11
  gem 'rubocop', '>= 0.79.0', require: false # For lint
12
- gem 'rubocop-minitest', '~> 0.10.1', require: false # For lint
13
- gem 'rubocop-performance', '~> 1.7.1', require: false # For lint
12
+ gem 'rubocop-minitest', '~> 0.10.3', require: false # For lint
13
+ gem 'rubocop-performance', '~> 1.9.2', require: false # For lint
14
+ gem 'rubocop-rake', '>= 0.5.1', require: false # For lint
14
15
  gem 'rubocop-sensible', '~> 0.3.0', require: false # For lint
16
+ gem 'yard', require: false
@@ -1,20 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- alba (0.10.0)
4
+ alba (0.13.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- activesupport (6.0.3.2)
9
+ activesupport (6.1.1)
10
10
  concurrent-ruby (~> 1.0, >= 1.0.2)
11
- i18n (>= 0.7, < 2)
12
- minitest (~> 5.1)
13
- tzinfo (~> 1.1)
14
- zeitwerk (~> 2.2, >= 2.2.2)
11
+ i18n (>= 1.6, < 2)
12
+ minitest (>= 5.1)
13
+ tzinfo (~> 2.0)
14
+ zeitwerk (~> 2.3)
15
15
  ast (2.4.1)
16
- bigdecimal (2.0.0)
17
- concurrent-ruby (1.1.6)
16
+ concurrent-ruby (1.1.7)
18
17
  coveralls (0.8.23)
19
18
  json (>= 1.8, < 3)
20
19
  simplecov (~> 0.16.1)
@@ -22,37 +21,39 @@ GEM
22
21
  thor (>= 0.19.4, < 2.0)
23
22
  tins (~> 1.6)
24
23
  docile (1.3.2)
25
- i18n (1.8.5)
24
+ i18n (1.8.7)
26
25
  concurrent-ruby (~> 1.0)
27
26
  json (2.3.1)
28
- minitest (5.14.1)
29
- oj (3.10.12)
30
- bigdecimal (>= 1.0, < 3)
31
- parallel (1.19.2)
32
- parser (2.7.1.4)
27
+ minitest (5.14.3)
28
+ oj (3.11.0)
29
+ parallel (1.20.1)
30
+ parser (3.0.0.0)
33
31
  ast (~> 2.4.1)
34
32
  rainbow (3.0.0)
35
- rake (13.0.1)
36
- regexp_parser (1.7.1)
33
+ rake (13.0.3)
34
+ regexp_parser (2.0.3)
37
35
  rexml (3.2.4)
38
- rubocop (0.89.1)
36
+ rubocop (1.8.1)
39
37
  parallel (~> 1.10)
40
- parser (>= 2.7.1.1)
38
+ parser (>= 3.0.0.0)
41
39
  rainbow (>= 2.2.2, < 4.0)
42
- regexp_parser (>= 1.7)
40
+ regexp_parser (>= 1.8, < 3.0)
43
41
  rexml
44
- rubocop-ast (>= 0.3.0, < 1.0)
42
+ rubocop-ast (>= 1.2.0, < 2.0)
45
43
  ruby-progressbar (~> 1.7)
46
- unicode-display_width (>= 1.4.0, < 2.0)
47
- rubocop-ast (0.3.0)
48
- parser (>= 2.7.1.4)
49
- rubocop-minitest (0.10.1)
50
- rubocop (>= 0.87)
51
- rubocop-performance (1.7.1)
52
- rubocop (>= 0.82.0)
44
+ unicode-display_width (>= 1.4.0, < 3.0)
45
+ rubocop-ast (1.4.0)
46
+ parser (>= 2.7.1.5)
47
+ rubocop-minitest (0.10.3)
48
+ rubocop (>= 0.87, < 2.0)
49
+ rubocop-performance (1.9.2)
50
+ rubocop (>= 0.90.0, < 2.0)
51
+ rubocop-ast (>= 0.4.0)
52
+ rubocop-rake (0.5.1)
53
+ rubocop
53
54
  rubocop-sensible (0.3.0)
54
55
  rubocop (>= 0.60.0)
55
- ruby-progressbar (1.10.1)
56
+ ruby-progressbar (1.11.0)
56
57
  simplecov (0.16.1)
57
58
  docile (~> 1.1)
58
59
  json (>= 1.8, < 3)
@@ -62,13 +63,13 @@ GEM
62
63
  term-ansicolor (1.7.1)
63
64
  tins (~> 1.0)
64
65
  thor (1.0.1)
65
- thread_safe (0.3.6)
66
66
  tins (1.25.0)
67
67
  sync
68
- tzinfo (1.2.7)
69
- thread_safe (~> 0.1)
70
- unicode-display_width (1.7.0)
71
- zeitwerk (2.4.0)
68
+ tzinfo (2.0.4)
69
+ concurrent-ruby (~> 1.0)
70
+ unicode-display_width (2.0.0)
71
+ yard (0.9.26)
72
+ zeitwerk (2.4.2)
72
73
 
73
74
  PLATFORMS
74
75
  ruby
@@ -77,13 +78,15 @@ DEPENDENCIES
77
78
  activesupport
78
79
  alba!
79
80
  coveralls
80
- minitest (~> 5.0)
81
- oj (~> 3.10)
81
+ minitest (~> 5.14)
82
+ oj (~> 3.11)
82
83
  rake (~> 13.0)
83
84
  rubocop (>= 0.79.0)
84
- rubocop-minitest (~> 0.10.1)
85
- rubocop-performance (~> 1.7.1)
85
+ rubocop-minitest (~> 0.10.3)
86
+ rubocop-performance (~> 1.9.2)
87
+ rubocop-rake (>= 0.5.1)
86
88
  rubocop-sensible (~> 0.3.0)
89
+ yard
87
90
 
88
91
  BUNDLED WITH
89
- 2.1.4
92
+ 2.2.6
data/README.md CHANGED
@@ -2,24 +2,26 @@
2
2
  [![Build Status](https://travis-ci.com/okuramasafumi/alba.svg?branch=master)](https://travis-ci.com/okuramasafumi/alba)
3
3
  [![Coverage Status](https://coveralls.io/repos/github/okuramasafumi/alba/badge.svg?branch=master)](https://coveralls.io/github/okuramasafumi/alba?branch=master)
4
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/fdab4cc0de0b9addcfe8/maintainability)](https://codeclimate.com/github/okuramasafumi/alba/maintainability)
5
+ ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/okuramasafumi/alba)
6
+ ![GitHub](https://img.shields.io/github/license/okuramasafumi/alba)
5
7
 
6
8
  # Alba
7
9
 
8
10
  `Alba` is the fastest JSON serializer for Ruby.
9
11
 
10
- # Why yet another JSON serializer?
12
+ ## Why yet another JSON serializer?
11
13
 
12
14
  We know that there are several other JSON serializers for Ruby around, but none of them made us satisfied.
13
15
 
14
16
  Alba has some advantages over other JSON serializers which we've wanted to have.
15
17
 
16
- ## Easy to understand
18
+ ### Easy to understand
17
19
 
18
20
  DSL is great. It makes the coding experience natural and intuitive. However, remembering lots of DSL requires us a lot of effort. Unfortunately, most of the existing libraries have implemented their features via DSL and it's not easy to understand how they behave entirely. Alba's core DSL are only four (`attributes`, `attribute`, `one` and `many`) so it's easy to understand how to use.
19
21
 
20
22
  Alba is also understandable internally. The codebase is much smaller than the alternatives. In fact, it's less than 300 lines of code. Look at the code on [GitHub](https://github.com/okuramasafumi/alba/tree/master/lib) and you'll be surprised how simple it is!
21
23
 
22
- ## Performance
24
+ ### Performance
23
25
 
24
26
  Alba is faster than most of the alternatives. We have a [benchmark](https://gist.github.com/okuramasafumi/4e375525bd3a28e4ca812d2a3b3e5829).
25
27
 
@@ -39,6 +41,36 @@ Or install it yourself as:
39
41
 
40
42
  $ gem install alba
41
43
 
44
+ ## Supported Ruby versions
45
+
46
+ Alba supports CRuby 2.5.7 and higher and latest TruffleRuby.
47
+
48
+ ## Documentation
49
+
50
+ You can find the documentation on [RubyDoc](https://rubydoc.info/gems/alba).
51
+
52
+ ## Features
53
+
54
+ * Resource-based serialization
55
+ * Arbitrary attribute definition
56
+ * One and many association with the ability to define them inline
57
+ * Adding condition and filter to association
58
+ * Parameters can be injected and used in attributes and associations
59
+ * Setting root key separately in Serializer
60
+ * Adding metadata
61
+ * Selectable backend
62
+ * No runtime dependencies
63
+
64
+ ## Anti features
65
+
66
+ * Sorting keys
67
+ * Class level support of parameters
68
+ * Supporting all existing JSON encoder/decoder
69
+ * Cache
70
+ * [JSON:API](https://jsonapi.org) support
71
+ * Association name inflection
72
+ * And many others
73
+
42
74
  ## Usage
43
75
 
44
76
  ### Configuration
@@ -125,7 +157,7 @@ class ArticleResource
125
157
  attributes :title
126
158
  end
127
159
 
128
- class UserResource1
160
+ class UserResource
129
161
  include Alba::Resource
130
162
 
131
163
  attributes :id
@@ -139,7 +171,7 @@ user.articles << article1
139
171
  article2 = Article.new(2, 'Super nice', 'Really nice!')
140
172
  user.articles << article2
141
173
 
142
- UserResource1.new(user).serialize
174
+ UserResource.new(user).serialize
143
175
  # => '{"id":1,"articles":[{"title":"Hello World!"},{"title":"Super nice"}]}'
144
176
  ```
145
177
 
@@ -189,6 +221,38 @@ RestrictedFooResouce.new(foo).serialize
189
221
  end
190
222
  ```
191
223
 
224
+ ### Attribute key transformation
225
+
226
+ ** Note: You need to install `active_support` gem to use `transform_keys` DSL.
227
+
228
+ With `active_support` installed, you can transform attribute keys.
229
+
230
+ ```ruby
231
+ class User
232
+ attr_reader :id, :first_name, :last_name
233
+
234
+ def initialize(id, first_name, last_name)
235
+ @id = id
236
+ @first_name = first_name
237
+ @last_name = last_name
238
+ end
239
+ end
240
+
241
+ class UserResource
242
+ include Alba::Resource
243
+
244
+ attributes :id, :first_name, :last_name
245
+
246
+ transform_keys :lower_camel
247
+ end
248
+
249
+ user = User.new(1, 'Masafumi', 'Okura')
250
+ UserResourceCamel.new(user).serialize
251
+ # => '{"id":1,"firstName":"Masafumi","lastName":"Okura"}'
252
+ ```
253
+
254
+ Supported transformation types are :camel, :lower_camel and :dash.
255
+
192
256
  ## Comparison
193
257
 
194
258
  Alba is faster than alternatives.
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.description = "Alba is designed to be a simple, easy to use and fast alternative to existing JSON serializers. Its performance is better than almost all gems which do similar things. The internal is so simple that it's easy to hack and maintain."
11
11
  spec.homepage = 'https://github.com/okuramasafumi/alba'
12
12
  spec.license = 'MIT'
13
- spec.required_ruby_version = Gem::Requirement.new('>= 2.5.8')
13
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5.7')
14
14
 
15
15
  spec.metadata['homepage_uri'] = spec.homepage
16
16
  spec.metadata['source_code_uri'] = 'https://github.com/okuramasafumi/alba'
@@ -1,23 +1,37 @@
1
- require 'alba/version'
2
- require 'alba/serializers/default_serializer'
3
- require 'alba/serializer'
4
- require 'alba/resource'
5
- require 'alba/resources/default_resource'
1
+ require_relative 'alba/version'
2
+ require_relative 'alba/serializer'
3
+ require_relative 'alba/resource'
6
4
 
7
5
  # Core module
8
6
  module Alba
7
+ # Base class for Errors
9
8
  class Error < StandardError; end
9
+
10
+ # Error class for backend which is not supported
10
11
  class UnsupportedBackend < Error; end
11
12
 
12
13
  class << self
13
14
  attr_reader :backend, :encoder
14
15
  attr_accessor :default_serializer
15
16
 
17
+ # Set the backend, which actually serializes object into JSON
18
+ #
19
+ # @param backend [#to_sym, nil] the name of the backend
20
+ # Possible values are `oj`, `active_support`, `default`, `json` and nil
21
+ # @return [Proc] the proc to encode object into JSON
22
+ # @raise [Alba::UnsupportedBackend] if backend is not supported
16
23
  def backend=(backend)
17
24
  @backend = backend&.to_sym
18
25
  set_encoder
19
26
  end
20
27
 
28
+ # Serialize the object with inline definitions
29
+ #
30
+ # @param object [Object] the object to be serialized
31
+ # @param with [nil, Proc, Alba::Serializer] selializer
32
+ # @param block [Block] resource block
33
+ # @return [String] serialized JSON string
34
+ # @raise [ArgumentError] if block is absent or `with` argument's type is wrong
21
35
  def serialize(object, with: nil, &block)
22
36
  raise ArgumentError, 'Block required' unless block
23
37
 
@@ -64,7 +78,10 @@ module Alba
64
78
  end
65
79
 
66
80
  def resource_class
67
- ::Alba::Resources::DefaultResource.clone
81
+ @resource_class ||= begin
82
+ klass = Class.new
83
+ klass.include(Alba::Resource)
84
+ end
68
85
  end
69
86
  end
70
87
 
@@ -2,6 +2,10 @@ module Alba
2
2
  # Base class for `One` and `Many`
3
3
  # Child class should implement `to_hash` method
4
4
  class Association
5
+ # @param name [Symbol] name of the method to fetch association
6
+ # @param condition [Proc] a proc filtering data
7
+ # @param resource [Class<Alba::Resource>] a resource class for the association
8
+ # @param block [Block] used to define resource when resource arg is absent
5
9
  def initialize(name:, condition: nil, resource: nil, &block)
6
10
  @name = name
7
11
  @condition = condition
@@ -10,6 +14,7 @@ module Alba
10
14
  raise ArgumentError, 'resource or block is required' if @resource.nil? && @block.nil?
11
15
  end
12
16
 
17
+ # @abstract
13
18
  def to_hash
14
19
  :not_implemented
15
20
  end
@@ -17,8 +22,8 @@ module Alba
17
22
  private
18
23
 
19
24
  def resource_class
20
- klass = ::Alba::Resources::DefaultResource.dup
21
- klass.reset
25
+ klass = Class.new
26
+ klass.include(Alba::Resource)
22
27
  klass.class_eval(&@block)
23
28
  klass
24
29
  end
@@ -0,0 +1,31 @@
1
+ module Alba
2
+ # Transform keys using `ActiveSupport::Inflector`
3
+ module KeyTransformer
4
+ begin
5
+ require 'active_support/inflector'
6
+ rescue LoadError
7
+ raise ::Alba::Error, 'To use transform_keys, please install `ActiveSupport` gem.'
8
+ end
9
+
10
+ module_function
11
+
12
+ # Transform key as given transform_type
13
+ #
14
+ # @params key [String] key to be transformed
15
+ # @params transform_type [Symbol] transform type
16
+ # @return [String] transformed key
17
+ # @raise [Alba::Error] when transform_type is not supported
18
+ def transform(key, transform_type)
19
+ case transform_type
20
+ when :camel
21
+ ActiveSupport::Inflector.camelize(key)
22
+ when :lower_camel
23
+ ActiveSupport::Inflector.camelize(key, false)
24
+ when :dash
25
+ ActiveSupport::Inflector.dasherize(key)
26
+ else
27
+ raise ::Alba::Error, "Unknown transform_type: #{transform_type}. Supported transform_type are :camel and :dash."
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,11 +1,16 @@
1
- require 'alba/association'
1
+ require_relative 'association'
2
2
 
3
3
  module Alba
4
4
  # Representing many association
5
5
  class Many < Association
6
+ # Recursively converts objects into an Array of Hashes
7
+ #
8
+ # @param target [Object] the object having an association method
9
+ # @param params [Hash] user-given Hash for arbitrary data
10
+ # @return [Array<Hash>]
6
11
  def to_hash(target, params: {})
7
12
  objects = target.public_send(@name)
8
- objects = @condition.call(objects) if @condition
13
+ objects = @condition.call(objects, params) if @condition
9
14
  objects.map { |o| @resource.new(o, params: params).to_hash }
10
15
  end
11
16
  end
@@ -1,11 +1,16 @@
1
- require 'alba/association'
1
+ require_relative 'association'
2
2
 
3
3
  module Alba
4
4
  # Representing one association
5
5
  class One < Association
6
+ # Recursively converts an object into a Hash
7
+ #
8
+ # @param target [Object] the object having an association method
9
+ # @param params [Hash] user-given Hash for arbitrary data
10
+ # @return [Hash]
6
11
  def to_hash(target, params: {})
7
12
  object = target.public_send(@name)
8
- object = @condition.call(object) if @condition
13
+ object = @condition.call(object, params) if @condition
9
14
  @resource.new(object, params: params).to_hash
10
15
  end
11
16
  end
@@ -1,12 +1,16 @@
1
- require 'alba/serializer'
2
- require 'alba/one'
3
- require 'alba/many'
4
- require 'alba/serializers/default_serializer'
1
+ require_relative 'serializer'
2
+ require_relative 'one'
3
+ require_relative 'many'
5
4
 
6
5
  module Alba
7
6
  # This module represents what should be serialized
8
7
  module Resource
9
- DSLS = {_attributes: {}, _serializer: nil, _key: nil}.freeze
8
+ # @!parse include InstanceMethods
9
+ # @!parse extend ClassMethods
10
+ DSLS = {_attributes: {}, _serializer: nil, _key: nil, _transform_keys: nil}.freeze
11
+ private_constant :DSLS
12
+
13
+ # @private
10
14
  def self.included(base)
11
15
  super
12
16
  base.class_eval do
@@ -23,16 +27,22 @@ module Alba
23
27
  module InstanceMethods
24
28
  attr_reader :object, :_key, :params
25
29
 
30
+ # @param object [Object] the object to be serialized
31
+ # @param params [Hash] user-given Hash for arbitrary data
26
32
  def initialize(object, params: {})
27
33
  @object = object
28
- @params = params
34
+ @params = params.freeze
29
35
  DSLS.each_key { |name| instance_variable_set("@#{name}", self.class.public_send(name)) }
30
36
  end
31
37
 
38
+ # Get serializer with `with` argument and serialize self with it
39
+ #
40
+ # @param with [nil, Proc, Alba::Serializer] selializer
41
+ # @return [String] serialized JSON string
32
42
  def serialize(with: nil)
33
43
  serializer = case with
34
44
  when nil
35
- @_serializer || Alba::Serializers::DefaultSerializer
45
+ @_serializer || empty_serializer
36
46
  when ->(obj) { obj.is_a?(Class) && obj <= Alba::Serializer }
37
47
  with
38
48
  when Proc
@@ -43,36 +53,60 @@ module Alba
43
53
  serializer.new(self).serialize
44
54
  end
45
55
 
56
+ # A Hash for serialization
57
+ #
58
+ # @return [Hash]
46
59
  def serializable_hash
47
60
  collection? ? @object.map(&converter) : converter.call(@object)
48
61
  end
49
62
  alias to_hash serializable_hash
50
63
 
64
+ # @return [Symbol]
51
65
  def key
52
66
  @_key || self.class.name.delete_suffix('Resource').downcase.gsub(/:{2}/, '_').to_sym
53
67
  end
54
68
 
55
69
  private
56
70
 
71
+ # rubocop:disable Style/MethodCalledOnDoEndBlock
57
72
  def converter
58
73
  lambda do |resource|
59
- @_attributes.transform_values do |attribute|
60
- case attribute
61
- when Symbol
62
- resource.public_send attribute
63
- when Proc
64
- instance_exec(resource, &attribute)
65
- when Alba::One, Alba::Many
66
- attribute.to_hash(resource, params: params)
67
- else
68
- raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
69
- end
70
- end
74
+ @_attributes.map do |key, attribute|
75
+ [transform_key(key), fetch_attribute(resource, attribute)]
76
+ end.to_h
77
+ end
78
+ end
79
+ # rubocop:enable Style/MethodCalledOnDoEndBlock
80
+
81
+ # Override this method to supply custom key transform method
82
+ def transform_key(key)
83
+ return key unless @_transform_keys
84
+
85
+ require_relative 'key_transformer'
86
+ KeyTransformer.transform(key, @_transform_keys)
87
+ end
88
+
89
+ def fetch_attribute(resource, attribute)
90
+ case attribute
91
+ when Symbol
92
+ resource.public_send attribute
93
+ when Proc
94
+ instance_exec(resource, &attribute)
95
+ when Alba::One, Alba::Many
96
+ attribute.to_hash(resource, params: params)
97
+ else
98
+ raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
71
99
  end
72
100
  end
73
101
 
102
+ def empty_serializer
103
+ klass = Class.new
104
+ klass.include Alba::Serializer
105
+ klass
106
+ end
107
+
74
108
  def inline_extended_serializer(with)
75
- klass = ::Alba::Serializers::DefaultSerializer.clone
109
+ klass = empty_serializer
76
110
  klass.class_eval(&with)
77
111
  klass
78
112
  end
@@ -86,43 +120,86 @@ module Alba
86
120
  module ClassMethods
87
121
  attr_reader(*DSLS.keys)
88
122
 
123
+ # @private
89
124
  def inherited(subclass)
90
125
  super
91
126
  DSLS.each_key { |name| subclass.instance_variable_set("@#{name}", instance_variable_get("@#{name}").clone) }
92
127
  end
93
128
 
129
+ # Set multiple attributes at once
130
+ #
131
+ # @param attrs [Array<String, Symbol>]
94
132
  def attributes(*attrs)
95
133
  attrs.each { |attr_name| @_attributes[attr_name.to_sym] = attr_name.to_sym }
96
134
  end
97
135
 
136
+ # Set an attribute with the given block
137
+ #
138
+ # @param name [String, Symbol] key name
139
+ # @param block [Block] the block called during serialization
140
+ # @raise [ArgumentError] if block is absent
98
141
  def attribute(name, &block)
99
142
  raise ArgumentError, 'No block given in attribute method' unless block
100
143
 
101
144
  @_attributes[name.to_sym] = block
102
145
  end
103
146
 
147
+ # Set One association
148
+ #
149
+ # @param name [String, Symbol]
150
+ # @param condition [Proc]
151
+ # @param resource [Class<Alba::Resource>]
152
+ # @param key [String, Symbol] used as key when given
153
+ # @param block [Block]
154
+ # @see Alba::One#initialize
104
155
  def one(name, condition = nil, resource: nil, key: nil, &block)
105
156
  @_attributes[key&.to_sym || name.to_sym] = One.new(name: name, condition: condition, resource: resource, &block)
106
157
  end
158
+ alias has_one one
107
159
 
160
+ # Set Many association
161
+ #
162
+ # @param name [String, Symbol]
163
+ # @param condition [Proc]
164
+ # @param resource [Class<Alba::Resource>]
165
+ # @param key [String, Symbol] used as key when given
166
+ # @param block [Block]
167
+ # @see Alba::Many#initialize
108
168
  def many(name, condition = nil, resource: nil, key: nil, &block)
109
169
  @_attributes[key&.to_sym || name.to_sym] = Many.new(name: name, condition: condition, resource: resource, &block)
110
170
  end
171
+ alias has_many many
111
172
 
173
+ # Set serializer for the resource
174
+ #
175
+ # @param name [Alba::Serializer]
112
176
  def serializer(name)
113
177
  @_serializer = name <= Alba::Serializer ? name : nil
114
178
  end
115
179
 
180
+ # Set key
181
+ #
182
+ # @param key [String, Symbol]
116
183
  def key(key)
117
184
  @_key = key.to_sym
118
185
  end
119
186
 
187
+ # Delete attributes
120
188
  # Use this DSL in child class to ignore certain attributes
189
+ #
190
+ # @param attributes [Array<String, Symbol>]
121
191
  def ignoring(*attributes)
122
192
  attributes.each do |attr_name|
123
193
  @_attributes.delete(attr_name.to_sym)
124
194
  end
125
195
  end
196
+
197
+ # Transform keys as specified type
198
+ #
199
+ # @params type [String, Symbol]
200
+ def transform_keys(type)
201
+ @_transform_keys = type.to_sym
202
+ end
126
203
  end
127
204
  end
128
205
  end
@@ -1,22 +1,36 @@
1
1
  module Alba
2
2
  # This module represents how a resource should be serialized.
3
3
  module Serializer
4
+ # @!parse include InstanceMethods
5
+ # @!parse extend ClassMethods
6
+
7
+ # @private
4
8
  def self.included(base)
5
9
  super
10
+ base.class_eval do
11
+ @_opts = {} unless instance_variable_defined?('@_opts')
12
+ @_metadata = {} unless instance_variable_defined?('@_metadata')
13
+ end
6
14
  base.include InstanceMethods
7
15
  base.extend ClassMethods
8
16
  end
9
17
 
10
18
  # Instance methods
11
19
  module InstanceMethods
20
+ # @param resource [Alba::Resource]
12
21
  def initialize(resource)
13
22
  @resource = resource
14
23
  @hash = resource.serializable_hash
15
24
  @hash = {key.to_sym => @hash} if key
25
+ return if metadata.empty?
26
+
16
27
  # @hash is either Hash or Array
17
28
  @hash.is_a?(Hash) ? @hash.merge!(metadata.to_h) : @hash << metadata
18
29
  end
19
30
 
31
+ # Use real encoder to actually serialize to JSON
32
+ #
33
+ # @return [String] JSON string
20
34
  def serialize
21
35
  Alba.encoder.call(@hash)
22
36
  end
@@ -24,12 +38,12 @@ module Alba
24
38
  private
25
39
 
26
40
  def key
27
- opts = self.class._opts || {}
41
+ opts = self.class._opts
28
42
  opts[:key] == true ? @resource.key : opts[:key]
29
43
  end
30
44
 
31
45
  def metadata
32
- metadata = self.class._metadata || {}
46
+ metadata = self.class._metadata
33
47
  metadata.transform_values { |block| block.call(@resource.object) }
34
48
  end
35
49
  end
@@ -38,19 +52,25 @@ module Alba
38
52
  module ClassMethods
39
53
  attr_reader :_opts, :_metadata
40
54
 
55
+ # @private
41
56
  def inherited(subclass)
42
57
  super
43
- %w[_opts _metadata].each { |name| subclass.instance_variable_set("@#{name}", instance_variable_get("@#{name}")) }
58
+ %w[_opts _metadata].each { |name| subclass.instance_variable_set("@#{name}", public_send(name).clone) }
44
59
  end
45
60
 
61
+ # Set options, currently key only
62
+ #
63
+ # @param key [Boolean, Symbol]
46
64
  def set(key: false)
47
- @_opts ||= {}
48
65
  @_opts[:key] = key
49
66
  end
50
67
 
68
+ # Set metadata
69
+ #
70
+ # @param name [String, Symbol] key for the metadata
71
+ # @param block [Block] the content of the metadata
51
72
  def metadata(name, &block)
52
- @_metadata ||= {}
53
- @_metadata[name] = block
73
+ @_metadata[name.to_sym] = block
54
74
  end
55
75
  end
56
76
  end
@@ -1,3 +1,3 @@
1
1
  module Alba
2
- VERSION = '0.10.0'.freeze
2
+ VERSION = '0.13.0'.freeze
3
3
  end
data/sider.yml CHANGED
@@ -7,6 +7,7 @@ linter:
7
7
  - "rubocop-minitest"
8
8
  - "rubocop-performance"
9
9
  - "rubocop-sensible"
10
+ - "rubocop-rake"
10
11
  safe: false
11
12
 
12
13
  # # https://help.sider.review/tools/ruby/reek
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alba
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OKURA Masafumi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-23 00:00:00.000000000 Z
11
+ date: 2021-01-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Alba is designed to be a simple, easy to use and fast alternative to
14
14
  existing JSON serializers. Its performance is better than almost all gems which
@@ -22,6 +22,7 @@ files:
22
22
  - ".gitignore"
23
23
  - ".rubocop.yml"
24
24
  - ".travis.yml"
25
+ - ".yardopts"
25
26
  - CODE_OF_CONDUCT.md
26
27
  - Gemfile
27
28
  - Gemfile.lock
@@ -33,12 +34,11 @@ files:
33
34
  - bin/setup
34
35
  - lib/alba.rb
35
36
  - lib/alba/association.rb
37
+ - lib/alba/key_transformer.rb
36
38
  - lib/alba/many.rb
37
39
  - lib/alba/one.rb
38
40
  - lib/alba/resource.rb
39
- - lib/alba/resources/default_resource.rb
40
41
  - lib/alba/serializer.rb
41
- - lib/alba/serializers/default_serializer.rb
42
42
  - lib/alba/version.rb
43
43
  - sider.yml
44
44
  homepage: https://github.com/okuramasafumi/alba
@@ -56,14 +56,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- version: 2.5.8
59
+ version: 2.5.7
60
60
  required_rubygems_version: !ruby/object:Gem::Requirement
61
61
  requirements:
62
62
  - - ">="
63
63
  - !ruby/object:Gem::Version
64
64
  version: '0'
65
65
  requirements: []
66
- rubygems_version: 3.1.4
66
+ rubygems_version: 3.0.3
67
67
  signing_key:
68
68
  specification_version: 4
69
69
  summary: Alba is the fastest JSON serializer for Ruby.
@@ -1,13 +0,0 @@
1
- module Alba
2
- module Resources
3
- # Empty resource class, use this with `class_eval` for
4
- # inline associations and serializations.
5
- class DefaultResource
6
- include Alba::Resource
7
-
8
- def self.reset
9
- @_attributes = {}
10
- end
11
- end
12
- end
13
- end
@@ -1,11 +0,0 @@
1
- require 'alba/serializer'
2
-
3
- module Alba
4
- module Serializers
5
- # DefaultSerializer class is used when a user doesn't specify serializer opt.
6
- # It's basically an alias of Alba::Serializer, but since it's a module this class simply include it.
7
- class DefaultSerializer
8
- include Alba::Serializer
9
- end
10
- end
11
- end