alba 0.9.0 → 0.12.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: 3a92c56eee7615f823efc93ed7edb87ba6c47a4bcf8e8b11e48edfc62c380545
4
- data.tar.gz: 310eca11a4a5a83287d3d87c1346c2436900bf1283e5642baa3878c69087812d
3
+ metadata.gz: ee2f8d482fedb98083c2acab37b425c7ecedb429ab7bae7698b4eea7949635d9
4
+ data.tar.gz: 1a44f23d425072253ba6743e18c6da9d8fa81de448b58720848c4e9667b12bfb
5
5
  SHA512:
6
- metadata.gz: 2fed0c44e90d2d876b2db635867741b3520a21c470acfb07a0218b7e0b627ce718edb1da964dfafdf0c79b3fe16bf7502a4fd873e998778c5307bd0c37d0c7c0
7
- data.tar.gz: 334edc5389f1fceba2ee880a322f894ccb145533793a885777ac29c08c273b5dda9a31cf9885b493b6ec3fabcf859a1d1643ce37b848c225db66b658b36e3e34
6
+ metadata.gz: 9bf421fcd99f06cb56499ee31c88dda019e004c58a1880c03326f2a1ce395f7dc4b64be7cee012169c7039530194e85a312b3c53d964b1aaf5288cdf8cb78ae4
7
+ data.tar.gz: 02f20dd839f72f9d2c1859b48470595fff263939f41421e240d74452677edae2dc0569078823984144f630cbc2e6000b6ac3bd0d4161a9ef65bd95dbf311294f
@@ -6,22 +6,47 @@ inherit_gem:
6
6
  require:
7
7
  - rubocop-minitest
8
8
  - rubocop-performance
9
+ - rubocop-rake
9
10
 
10
11
  AllCops:
11
12
  Exclude:
12
13
  - 'Rakefile'
13
14
  - 'alba.gemspec'
14
15
  NewCops: enable
16
+ EnabledByDefault: true
17
+
18
+ # Oneline comment is not valid so until it gets valid, we disable it
19
+ Bundler/GemComment:
20
+ Enabled: false
15
21
 
16
22
  Layout/SpaceInsideHashLiteralBraces:
17
23
  EnforcedStyle: no_space
18
24
 
25
+ Layout/MultilineAssignmentLayout:
26
+ EnforcedStyle: same_line
27
+
28
+ Lint/ConstantResolution:
29
+ Enabled: false
30
+
19
31
  Metrics/ClassLength:
20
32
  Exclude:
21
33
  - 'test/alba_test.rb'
22
34
 
23
35
  Metrics/MethodLength:
24
- Max: 20
36
+ Max: 15
37
+
38
+ Style/ConstantVisibility:
39
+ Exclude:
40
+ - 'lib/alba/version.rb'
41
+
42
+ Style/Copyright:
43
+ Enabled: false
25
44
 
26
45
  Style/FrozenStringLiteralComment:
27
46
  Enabled: false
47
+
48
+ Style/InlineComment:
49
+ Enabled: false
50
+
51
+ Style/MethodCallWithArgsParentheses:
52
+ Enabled: false
@@ -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
@@ -3,12 +3,14 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in alba.gemspec
4
4
  gemspec
5
5
 
6
- gem 'activesupport', require: false
7
- gem 'coveralls', require: false
8
- gem 'minitest', '~> 5.0'
9
- gem 'oj', '~> 3.10', platforms: :ruby
10
- gem 'rake', '~> 13.0'
11
- gem 'rubocop', '>= 0.79.0', require: false
12
- gem 'rubocop-minitest', '~> 0.10.1', require: false
13
- gem 'rubocop-performance', '~> 1.7.1', require: false
14
- gem 'rubocop-sensible', '~> 0.3.0', require: false
6
+ gem 'activesupport', require: false # For backend
7
+ gem 'coveralls', require: false # For test coverage
8
+ gem 'minitest', '~> 5.14' # For test
9
+ gem 'oj', '~> 3.11', platform: :ruby, require: false # For backend
10
+ gem 'rake', '~> 13.0' # For test and automation
11
+ gem 'rubocop', '>= 0.79.0', 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
15
+ gem 'rubocop-sensible', '~> 0.3.0', require: false # For lint
16
+ gem 'yard', require: false
@@ -1,19 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- alba (0.9.0)
4
+ alba (0.12.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
- concurrent-ruby (1.1.6)
16
+ concurrent-ruby (1.1.7)
17
17
  coveralls (0.8.23)
18
18
  json (>= 1.8, < 3)
19
19
  simplecov (~> 0.16.1)
@@ -21,36 +21,39 @@ GEM
21
21
  thor (>= 0.19.4, < 2.0)
22
22
  tins (~> 1.6)
23
23
  docile (1.3.2)
24
- i18n (1.8.5)
24
+ i18n (1.8.7)
25
25
  concurrent-ruby (~> 1.0)
26
26
  json (2.3.1)
27
- minitest (5.14.1)
28
- oj (3.10.8)
29
- parallel (1.19.2)
30
- 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)
31
31
  ast (~> 2.4.1)
32
32
  rainbow (3.0.0)
33
- rake (13.0.1)
34
- regexp_parser (1.7.1)
33
+ rake (13.0.3)
34
+ regexp_parser (2.0.3)
35
35
  rexml (3.2.4)
36
- rubocop (0.89.1)
36
+ rubocop (1.8.1)
37
37
  parallel (~> 1.10)
38
- parser (>= 2.7.1.1)
38
+ parser (>= 3.0.0.0)
39
39
  rainbow (>= 2.2.2, < 4.0)
40
- regexp_parser (>= 1.7)
40
+ regexp_parser (>= 1.8, < 3.0)
41
41
  rexml
42
- rubocop-ast (>= 0.3.0, < 1.0)
42
+ rubocop-ast (>= 1.2.0, < 2.0)
43
43
  ruby-progressbar (~> 1.7)
44
- unicode-display_width (>= 1.4.0, < 2.0)
45
- rubocop-ast (0.3.0)
46
- parser (>= 2.7.1.4)
47
- rubocop-minitest (0.10.1)
48
- rubocop (>= 0.87)
49
- rubocop-performance (1.7.1)
50
- 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
51
54
  rubocop-sensible (0.3.0)
52
55
  rubocop (>= 0.60.0)
53
- ruby-progressbar (1.10.1)
56
+ ruby-progressbar (1.11.0)
54
57
  simplecov (0.16.1)
55
58
  docile (~> 1.1)
56
59
  json (>= 1.8, < 3)
@@ -60,13 +63,13 @@ GEM
60
63
  term-ansicolor (1.7.1)
61
64
  tins (~> 1.0)
62
65
  thor (1.0.1)
63
- thread_safe (0.3.6)
64
66
  tins (1.25.0)
65
67
  sync
66
- tzinfo (1.2.7)
67
- thread_safe (~> 0.1)
68
- unicode-display_width (1.7.0)
69
- 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)
70
73
 
71
74
  PLATFORMS
72
75
  ruby
@@ -75,13 +78,15 @@ DEPENDENCIES
75
78
  activesupport
76
79
  alba!
77
80
  coveralls
78
- minitest (~> 5.0)
79
- oj (~> 3.10)
81
+ minitest (~> 5.14)
82
+ oj (~> 3.11)
80
83
  rake (~> 13.0)
81
84
  rubocop (>= 0.79.0)
82
- rubocop-minitest (~> 0.10.1)
83
- rubocop-performance (~> 1.7.1)
85
+ rubocop-minitest (~> 0.10.3)
86
+ rubocop-performance (~> 1.9.2)
87
+ rubocop-rake (>= 0.5.1)
84
88
  rubocop-sensible (~> 0.3.0)
89
+ yard
85
90
 
86
91
  BUNDLED WITH
87
- 2.1.4
92
+ 2.2.6
data/README.md CHANGED
@@ -2,11 +2,29 @@
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
 
12
+ ## Why yet another JSON serializer?
13
+
14
+ We know that there are several other JSON serializers for Ruby around, but none of them made us satisfied.
15
+
16
+ Alba has some advantages over other JSON serializers which we've wanted to have.
17
+
18
+ ### Easy to understand
19
+
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.
21
+
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!
23
+
24
+ ### Performance
25
+
26
+ Alba is faster than most of the alternatives. We have a [benchmark](https://gist.github.com/okuramasafumi/4e375525bd3a28e4ca812d2a3b3e5829).
27
+
10
28
  ## Installation
11
29
 
12
30
  Add this line to your application's Gemfile:
@@ -23,6 +41,36 @@ Or install it yourself as:
23
41
 
24
42
  $ gem install alba
25
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
+
26
74
  ## Usage
27
75
 
28
76
  ### Configuration
@@ -109,7 +157,7 @@ class ArticleResource
109
157
  attributes :title
110
158
  end
111
159
 
112
- class UserResource1
160
+ class UserResource
113
161
  include Alba::Resource
114
162
 
115
163
  attributes :id
@@ -123,7 +171,7 @@ user.articles << article1
123
171
  article2 = Article.new(2, 'Super nice', 'Really nice!')
124
172
  user.articles << article2
125
173
 
126
- UserResource1.new(user).serialize
174
+ UserResource.new(user).serialize
127
175
  # => '{"id":1,"articles":[{"title":"Hello World!"},{"title":"Super nice"}]}'
128
176
  ```
129
177
 
@@ -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,22 +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
10
9
 
10
+ # Error class for backend which is not supported
11
+ class UnsupportedBackend < Error; end
12
+
11
13
  class << self
12
14
  attr_reader :backend, :encoder
13
15
  attr_accessor :default_serializer
14
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
15
23
  def backend=(backend)
16
24
  @backend = backend&.to_sym
17
25
  set_encoder
18
26
  end
19
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
20
35
  def serialize(object, with: nil, &block)
21
36
  raise ArgumentError, 'Block required' unless block
22
37
 
@@ -31,26 +46,30 @@ module Alba
31
46
  def set_encoder
32
47
  @encoder = case @backend
33
48
  when :oj
34
- begin
35
- require 'oj'
36
- ->(hash) { Oj.dump(hash, mode: :strict) }
37
- rescue LoadError
38
- default_encoder
39
- end
49
+ try_oj
40
50
  when :active_support
41
- begin
42
- require 'active_support/json'
43
- ->(hash) { ActiveSupport::JSON.encode(hash) }
44
- rescue LoadError
45
- default_encoder
46
- end
51
+ try_active_support
47
52
  when nil, :default, :json
48
53
  default_encoder
49
54
  else
50
- raise Alba::Error, "Unsupported backend, #{backend}"
55
+ raise Alba::UnsupportedBackend, "Unsupported backend, #{backend}"
51
56
  end
52
57
  end
53
58
 
59
+ def try_oj
60
+ require 'oj'
61
+ ->(hash) { Oj.dump(hash, mode: :strict) }
62
+ rescue LoadError
63
+ default_encoder
64
+ end
65
+
66
+ def try_active_support
67
+ require 'active_support/json'
68
+ ->(hash) { ActiveSupport::JSON.encode(hash) }
69
+ rescue LoadError
70
+ default_encoder
71
+ end
72
+
54
73
  def default_encoder
55
74
  lambda do |hash|
56
75
  require 'json'
@@ -59,7 +78,10 @@ module Alba
59
78
  end
60
79
 
61
80
  def resource_class
62
- ::Alba::Resources::DefaultResource.clone
81
+ @resource_class ||= begin
82
+ klass = Class.new
83
+ klass.include(Alba::Resource)
84
+ end
63
85
  end
64
86
  end
65
87
 
@@ -2,13 +2,19 @@ module Alba
2
2
  # Base class for `One` and `Many`
3
3
  # Child class should implement `to_hash` method
4
4
  class Association
5
- def initialize(name:, resource: nil, &block)
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
9
+ def initialize(name:, condition: nil, resource: nil, &block)
6
10
  @name = name
7
- @resource = resource
11
+ @condition = condition
8
12
  @block = block
13
+ @resource = resource || resource_class
9
14
  raise ArgumentError, 'resource or block is required' if @resource.nil? && @block.nil?
10
15
  end
11
16
 
17
+ # @abstract
12
18
  def to_hash
13
19
  :not_implemented
14
20
  end
@@ -16,8 +22,8 @@ module Alba
16
22
  private
17
23
 
18
24
  def resource_class
19
- klass = ::Alba::Resources::DefaultResource.dup
20
- klass.reset
25
+ klass = Class.new
26
+ klass.include(Alba::Resource)
21
27
  klass.class_eval(&@block)
22
28
  klass
23
29
  end
@@ -1,12 +1,17 @@
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
- def to_hash(target)
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>]
11
+ def to_hash(target, params: {})
7
12
  objects = target.public_send(@name)
8
- @resource ||= resource_class
9
- objects.map { |o| @resource.new(o).to_hash }
13
+ objects = @condition.call(objects, params) if @condition
14
+ objects.map { |o| @resource.new(o, params: params).to_hash }
10
15
  end
11
16
  end
12
17
  end
@@ -1,12 +1,17 @@
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
- def to_hash(target)
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]
11
+ def to_hash(target, params: {})
7
12
  object = target.public_send(@name)
8
- @resource ||= resource_class
9
- @resource.new(object).to_hash
13
+ object = @condition.call(object, params) if @condition
14
+ @resource.new(object, params: params).to_hash
10
15
  end
11
16
  end
12
17
  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
8
+ # @!parse include InstanceMethods
9
+ # @!parse extend ClassMethods
9
10
  DSLS = {_attributes: {}, _serializer: nil, _key: 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,11 +53,15 @@ 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
@@ -63,14 +77,22 @@ module Alba
63
77
  when Proc
64
78
  instance_exec(resource, &attribute)
65
79
  when Alba::One, Alba::Many
66
- attribute.to_hash(resource)
80
+ attribute.to_hash(resource, params: params)
81
+ else
82
+ raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
67
83
  end
68
84
  end
69
85
  end
70
86
  end
71
87
 
88
+ def empty_serializer
89
+ klass = Class.new
90
+ klass.include Alba::Serializer
91
+ klass
92
+ end
93
+
72
94
  def inline_extended_serializer(with)
73
- klass = ::Alba::Serializers::DefaultSerializer.clone
95
+ klass = empty_serializer
74
96
  klass.class_eval(&with)
75
97
  klass
76
98
  end
@@ -84,41 +106,77 @@ module Alba
84
106
  module ClassMethods
85
107
  attr_reader(*DSLS.keys)
86
108
 
109
+ # @private
87
110
  def inherited(subclass)
88
111
  super
89
112
  DSLS.each_key { |name| subclass.instance_variable_set("@#{name}", instance_variable_get("@#{name}").clone) }
90
113
  end
91
114
 
115
+ # Set multiple attributes at once
116
+ #
117
+ # @param attrs [Array<String, Symbol>]
92
118
  def attributes(*attrs)
93
- attrs.each { |attr_name| @_attributes[attr_name] = attr_name }
119
+ attrs.each { |attr_name| @_attributes[attr_name.to_sym] = attr_name.to_sym }
94
120
  end
95
121
 
122
+ # Set an attribute with the given block
123
+ #
124
+ # @param name [String, Symbol] key name
125
+ # @param block [Block] the block called during serialization
126
+ # @raise [ArgumentError] if block is absent
96
127
  def attribute(name, &block)
97
128
  raise ArgumentError, 'No block given in attribute method' unless block
98
129
 
99
- @_attributes[name] = block
100
- end
101
-
102
- def one(name, resource: nil, &block)
103
- @_attributes[name.to_sym] = One.new(name: name, resource: resource, &block)
104
- end
105
-
106
- def many(name, resource: nil, &block)
107
- @_attributes[name.to_sym] = Many.new(name: name, resource: resource, &block)
108
- end
109
-
130
+ @_attributes[name.to_sym] = block
131
+ end
132
+
133
+ # Set One association
134
+ #
135
+ # @param name [String, Symbol]
136
+ # @param condition [Proc]
137
+ # @param resource [Class<Alba::Resource>]
138
+ # @param key [String, Symbol] used as key when given
139
+ # @param block [Block]
140
+ # @see Alba::One#initialize
141
+ def one(name, condition = nil, resource: nil, key: nil, &block)
142
+ @_attributes[key&.to_sym || name.to_sym] = One.new(name: name, condition: condition, resource: resource, &block)
143
+ end
144
+ alias has_one one
145
+
146
+ # Set Many association
147
+ #
148
+ # @param name [String, Symbol]
149
+ # @param condition [Proc]
150
+ # @param resource [Class<Alba::Resource>]
151
+ # @param key [String, Symbol] used as key when given
152
+ # @param block [Block]
153
+ # @see Alba::Many#initialize
154
+ def many(name, condition = nil, resource: nil, key: nil, &block)
155
+ @_attributes[key&.to_sym || name.to_sym] = Many.new(name: name, condition: condition, resource: resource, &block)
156
+ end
157
+ alias has_many many
158
+
159
+ # Set serializer for the resource
160
+ #
161
+ # @param name [Alba::Serializer]
110
162
  def serializer(name)
111
163
  @_serializer = name <= Alba::Serializer ? name : nil
112
164
  end
113
165
 
166
+ # Set key
167
+ #
168
+ # @param key [String, Symbol]
114
169
  def key(key)
115
170
  @_key = key.to_sym
116
171
  end
117
172
 
173
+ # Delete attributes
118
174
  # Use this DSL in child class to ignore certain attributes
175
+ #
176
+ # @param attributes [Array<String, Symbol>]
119
177
  def ignoring(*attributes)
120
178
  attributes.each do |attr_name|
121
- @_attributes.delete(attr_name)
179
+ @_attributes.delete(attr_name.to_sym)
122
180
  end
123
181
  end
124
182
  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
16
25
  # @hash is either Hash or Array
17
- @hash.is_a?(Hash) ? @hash.merge!(metadata.to_h) : @hash << metadata
26
+ unless metadata.empty?
27
+ @hash.is_a?(Hash) ? @hash.merge!(metadata.to_h) : @hash << metadata
28
+ end
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,17 +38,12 @@ module Alba
24
38
  private
25
39
 
26
40
  def key
27
- opts = self.class._opts || {}
28
- case opts[:key]
29
- when true
30
- @resource.key
31
- else
32
- opts[:key]
33
- end
41
+ opts = self.class._opts
42
+ opts[:key] == true ? @resource.key : opts[:key]
34
43
  end
35
44
 
36
45
  def metadata
37
- metadata = self.class._metadata || {}
46
+ metadata = self.class._metadata
38
47
  metadata.transform_values { |block| block.call(@resource.object) }
39
48
  end
40
49
  end
@@ -43,19 +52,25 @@ module Alba
43
52
  module ClassMethods
44
53
  attr_reader :_opts, :_metadata
45
54
 
55
+ # @private
46
56
  def inherited(subclass)
47
57
  super
48
- %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) }
49
59
  end
50
60
 
61
+ # Set options, currently key only
62
+ #
63
+ # @param key [Boolean, Symbol]
51
64
  def set(key: false)
52
- @_opts ||= {}
53
65
  @_opts[:key] = key
54
66
  end
55
67
 
68
+ # Set metadata
69
+ #
70
+ # @param name [String, Symbol] key for the metadata
71
+ # @param block [Block] the content of the metadata
56
72
  def metadata(name, &block)
57
- @_metadata ||= {}
58
- @_metadata[name] = block
73
+ @_metadata[name.to_sym] = block
59
74
  end
60
75
  end
61
76
  end
@@ -1,3 +1,3 @@
1
1
  module Alba
2
- VERSION = '0.9.0'.freeze
2
+ VERSION = '0.12.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.9.0
4
+ version: 0.12.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-11 00:00:00.000000000 Z
11
+ date: 2021-01-20 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
@@ -36,9 +37,7 @@ files:
36
37
  - lib/alba/many.rb
37
38
  - lib/alba/one.rb
38
39
  - lib/alba/resource.rb
39
- - lib/alba/resources/default_resource.rb
40
40
  - lib/alba/serializer.rb
41
- - lib/alba/serializers/default_serializer.rb
42
41
  - lib/alba/version.rb
43
42
  - sider.yml
44
43
  homepage: https://github.com/okuramasafumi/alba
@@ -56,14 +55,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
56
55
  requirements:
57
56
  - - ">="
58
57
  - !ruby/object:Gem::Version
59
- version: 2.5.8
58
+ version: 2.5.7
60
59
  required_rubygems_version: !ruby/object:Gem::Requirement
61
60
  requirements:
62
61
  - - ">="
63
62
  - !ruby/object:Gem::Version
64
63
  version: '0'
65
64
  requirements: []
66
- rubygems_version: 3.1.4
65
+ rubygems_version: 3.0.3
67
66
  signing_key:
68
67
  specification_version: 4
69
68
  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