alba 0.2.0 → 0.7.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: 9dab0921e07fb607cfceb802a42fdb5f8cc20eb745522c46dc7b451b8a0cd14e
4
- data.tar.gz: 6c6fcc0035ef543ee6d60bffa18ca83379d090e800950411d7316c21031784ad
3
+ metadata.gz: 405e177e9e1fcadf7dbb164d3ac6924e1b3563547f715fedb698211b527a9604
4
+ data.tar.gz: 2c534708583345ac9090c83b3ddc939b0c8bd335ed77017f554edb28578d0396
5
5
  SHA512:
6
- metadata.gz: c97545976f850ba0191dcabf7f34b8daeebf54d2b82c9a37305f569cc7cadaa1b9f0f92dc42f81193e9fd56eae2e862d650b023c4bcd105739c18c0baaf35e13
7
- data.tar.gz: 7423763628b13e5643193347379eefbcf2cc2d78266cafd147d8c86d3f755feca93dd3f2c9bca92e8ec008b1ec7d00c9ed7bf1590a2f26e83c99fa529a987de1
6
+ metadata.gz: 71f4712ac28d457fe9bf997fb127288ed66d7d2231ffd6dd438b2eb5c1dd82ff9e3e5c4000415c513012a582cda3d3c3e73fdf0beb4cc96b8583ff9a658dfa75
7
+ data.tar.gz: '07439ccffc5b48a0d5d4286236acadf4cc3e89ff1afa0a882a87c1fe5640015096a4cd85839cebdc4d6ef350a77043a494bfe4d7b6cff99f8e7db2ab9f8b3db0'
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ gemspec
5
5
 
6
6
  gem 'coveralls', require: false
7
7
  gem 'minitest', '~> 5.0'
8
+ gem 'oj', '~> 3.10'
8
9
  gem 'rake', '~> 13.0'
9
10
  gem 'rubocop', '>= 0.79.0', require: false
10
11
  gem 'rubocop-performance', '~> 1.7.1', require: false
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- alba (0.2.0)
4
+ alba (0.7.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -16,6 +16,7 @@ GEM
16
16
  docile (1.3.2)
17
17
  json (2.3.1)
18
18
  minitest (5.14.1)
19
+ oj (3.10.8)
19
20
  parallel (1.19.2)
20
21
  parser (2.7.1.4)
21
22
  ast (~> 2.4.1)
@@ -59,6 +60,7 @@ DEPENDENCIES
59
60
  alba!
60
61
  coveralls
61
62
  minitest (~> 5.0)
63
+ oj (~> 3.10)
62
64
  rake (~> 13.0)
63
65
  rubocop (>= 0.79.0)
64
66
  rubocop-performance (~> 1.7.1)
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # Alba
6
6
 
7
- `Alba` is a fast and flexible JSON serializer.
7
+ `Alba` is a stupid, fast and easy to use JSON serializer.
8
8
 
9
9
  ## Installation
10
10
 
@@ -24,6 +24,8 @@ Or install it yourself as:
24
24
 
25
25
  ## Usage
26
26
 
27
+ ### Simple serialization with key
28
+
27
29
  ```ruby
28
30
  class User
29
31
  attr_accessor :id, :name, :email, :created_at, :updated_at
@@ -57,6 +59,80 @@ UserResource.new(user).serialize
57
59
  # => "{\"id\":1,\"name\":\"Masafumi OKURA\",\"name_with_email\":\"Masafumi OKURA: masafumi@example.com\"}"
58
60
  ```
59
61
 
62
+ ### Serialization with associations
63
+
64
+ ```ruby
65
+ class User
66
+ attr_reader :id, :created_at, :updated_at
67
+ attr_accessor :articles
68
+
69
+ def initialize(id)
70
+ @id = id
71
+ @created_at = Time.now
72
+ @updated_at = Time.now
73
+ @articles = []
74
+ end
75
+ end
76
+
77
+ class Article
78
+ attr_accessor :user_id, :title, :body
79
+
80
+ def initialize(user_id, title, body)
81
+ @user_id = user_id
82
+ @title = title
83
+ @body = body
84
+ end
85
+ end
86
+
87
+ class ArticleResource
88
+ include Alba::Resource
89
+
90
+ attributes :title
91
+ end
92
+
93
+ class UserResource1
94
+ include Alba::Resource
95
+
96
+ attributes :id
97
+
98
+ many :articles, resource: ArticleResource
99
+ end
100
+
101
+ user = User.new(1)
102
+ article1 = Article.new(1, 'Hello World!', 'Hello World!!!')
103
+ user.articles << article1
104
+ article2 = Article.new(2, 'Super nice', 'Really nice!')
105
+ user.articles << article2
106
+
107
+ UserResource1.new(user).serialize
108
+ # => '{"id":1,"articles":[{"title":"Hello World!"},{"title":"Super nice"}]}'
109
+ ```
110
+
111
+ ### Inline definition with `Alba.serialize`
112
+
113
+ `Alba.serialize` method is a shortcut to define everything inline.
114
+
115
+ ```ruby
116
+ Alba.serialize(user, with: proc { set key: :foo }) do
117
+ attributes :id
118
+ many :articles do
119
+ attributes :title, :body
120
+ end
121
+ end
122
+ # => '{"foo":{"id":1,"articles":[{"title":"Hello World!","body":"Hello World!!!"},{"title":"Super nice","body":"Really nice!"}]}}'
123
+ ```
124
+
125
+ Although this might be useful sometimes, it's generally recommended to define a class for both Resource and Serializer.
126
+
127
+ ## Comparison
128
+
129
+ Since Alba is intended to be stupid, there are many things Alba can't do while other gems can. However, from the same reason, it's extremely faster than alternatives.
130
+ For a performance benchmark, see https://gist.github.com/okuramasafumi/4e375525bd3a28e4ca812d2a3b3e5829.
131
+
132
+ ## Why named "Alba"?
133
+
134
+ The name "Alba" comes from "albatross", a kind of birds. In Japanese, this bird is called "Aho-dori", which means "stupid bird". I find it funny because in fact albatrosses fly really fast. I hope Alba looks stupid but in fact it does its job quick.
135
+
60
136
  ## Development
61
137
 
62
138
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -1,6 +1,8 @@
1
1
  require 'alba/version'
2
+ require 'alba/serializers/default_serializer'
3
+ require 'alba/serializer'
2
4
  require 'alba/resource'
3
- require 'json'
5
+ require 'alba/resources/default_resource'
4
6
 
5
7
  # Core module
6
8
  module Alba
@@ -8,24 +10,25 @@ module Alba
8
10
 
9
11
  class << self
10
12
  attr_reader :backend
11
- end
13
+ attr_accessor :default_serializer
12
14
 
13
- def self.backend=(backend)
14
- @backend = backend&.to_sym
15
- end
15
+ def backend=(backend)
16
+ @backend = backend&.to_sym
17
+ end
18
+
19
+ def serialize(object, with: nil, &block)
20
+ raise ArgumentError, 'Block required' unless block
21
+
22
+ resource_class.class_eval(&block)
23
+ resource = resource_class.new(object)
24
+ with ||= @default_serializer
25
+ resource.serialize(with: with)
26
+ end
27
+
28
+ private
16
29
 
17
- def self.serialize(object)
18
- fallback = ->(resource) { resource.to_json }
19
- case backend
20
- when :oj
21
- begin
22
- require 'oj'
23
- ->(resource) { Oj.dump(resource) }
24
- rescue LoadError
25
- fallback
26
- end
27
- else
28
- fallback
29
- end.call(object)
30
+ def resource_class
31
+ ::Alba::Resources::DefaultResource.clone
32
+ end
30
33
  end
31
34
  end
@@ -9,7 +9,7 @@ module Alba
9
9
  end
10
10
 
11
11
  def to_hash(target)
12
- objects = target.__send__(@name)
12
+ objects = target.public_send(@name)
13
13
  @resource ||= resource_class
14
14
  objects.map { |o| @resource.new(o).to_hash }
15
15
  end
@@ -9,7 +9,7 @@ module Alba
9
9
  end
10
10
 
11
11
  def to_hash(target)
12
- object = target.__send__(@name)
12
+ object = target.public_send(@name)
13
13
  @resource ||= resource_class
14
14
  @resource.new(object).to_hash
15
15
  end
@@ -7,12 +7,17 @@ require 'alba/serializers/default_serializer'
7
7
  module Alba
8
8
  # This module represents what should be serialized
9
9
  module Resource
10
- DSLS = [:_attributes, :_one, :_many, :_serializer].freeze
10
+ DSLS = [:_attributes, :_serializer, :_key].freeze
11
11
  def self.included(base)
12
12
  base.class_eval do
13
13
  # Initialize
14
14
  DSLS.each do |name|
15
- initial = name == :_serializer ? nil : {}
15
+ initial = case name
16
+ when :_attributes
17
+ {}
18
+ when :_serializer, :_name
19
+ nil
20
+ end
16
21
  instance_variable_set("@#{name}", initial) unless instance_variable_defined?("@#{name}")
17
22
  end
18
23
  end
@@ -29,41 +34,47 @@ module Alba
29
34
 
30
35
  def serialize(with: nil)
31
36
  serializer = case with
32
- when ->(obj) { obj.is_a?(Class) && obj <= Alba::Serializer }
33
- with
34
- when Symbol
35
- const_get(with.to_s.capitalize)
36
- when String
37
- const_get(with)
38
37
  when nil
39
38
  @_serializer || Alba::Serializers::DefaultSerializer
39
+ when ->(obj) { obj.is_a?(Class) && obj <= Alba::Serializer }
40
+ with
41
+ when Proc
42
+ inline_extended_serializer(with)
43
+ else
44
+ raise ArgumentError, 'Unexpected type for with, possible types are Class or Proc'
40
45
  end
41
- serializer.new(serializable_hash).serialize
46
+ serializer.new(self).serialize
42
47
  end
43
48
 
44
- def serializable_hash
45
- attrs.merge(ones).merge(manies)
49
+ def serializable_hash(with_key: true)
50
+ get_attribute = lambda do |resource|
51
+ @_attributes.transform_values do |attribute|
52
+ attribute.to_hash(resource)
53
+ end
54
+ end
55
+ serializable_hash = if collection?
56
+ @_resource.map(&get_attribute)
57
+ else
58
+ get_attribute.call(@_resource)
59
+ end
60
+ with_key && @_key ? {@_key => serializable_hash} : serializable_hash
46
61
  end
47
62
  alias to_hash serializable_hash
48
63
 
49
- private
50
-
51
- def attrs
52
- @_attributes.transform_values do |attribute|
53
- attribute.to_hash(@_resource)
54
- end || {}
64
+ def key
65
+ @_key || self.class.name.delete_suffix('Resource').downcase.gsub(/:{2}/, '_').to_sym
55
66
  end
56
67
 
57
- def ones
58
- @_one.transform_values do |one|
59
- one.to_hash(@_resource)
60
- end || {}
68
+ private
69
+
70
+ def inline_extended_serializer(with)
71
+ klass = ::Alba::Serializers::DefaultSerializer.clone
72
+ klass.class_eval(&with)
73
+ klass
61
74
  end
62
75
 
63
- def manies
64
- @_many.transform_values do |many|
65
- many.to_hash(@_resource)
66
- end || {}
76
+ def collection?
77
+ @_resource.is_a?(Enumerable)
67
78
  end
68
79
  end
69
80
 
@@ -86,16 +97,20 @@ module Alba
86
97
  end
87
98
 
88
99
  def one(name, resource: nil, &block)
89
- @_one[name.to_sym] = One.new(name: name, resource: resource, &block)
100
+ @_attributes[name.to_sym] = One.new(name: name, resource: resource, &block)
90
101
  end
91
102
 
92
103
  def many(name, resource: nil, &block)
93
- @_many[name.to_sym] = Many.new(name: name, resource: resource, &block)
104
+ @_attributes[name.to_sym] = Many.new(name: name, resource: resource, &block)
94
105
  end
95
106
 
96
107
  def serializer(name)
97
108
  @_serializer = name <= Alba::Serializer ? name : nil
98
109
  end
110
+
111
+ def key(key)
112
+ @_key = key.to_sym
113
+ end
99
114
  end
100
115
  end
101
116
  end
@@ -0,0 +1,9 @@
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
+ end
8
+ end
9
+ end
@@ -1,6 +1,5 @@
1
1
  module Alba
2
2
  # This module represents how a resource should be serialized.
3
- #
4
3
  module Serializer
5
4
  def self.included(base)
6
5
  base.include InstanceMethods
@@ -10,19 +9,27 @@ module Alba
10
9
  # Instance methods
11
10
  module InstanceMethods
12
11
  def initialize(resource)
13
- @_resource = resource
14
12
  @_opts = self.class._opts || {}
15
- key = @_opts[:key]
16
- @_resource = {key.to_sym => @_resource} if key
13
+ key = case @_opts[:key]
14
+ when true
15
+ resource.key
16
+ else
17
+ @_opts[:key]
18
+ end
19
+ @hash = resource.serializable_hash(with_key: false)
20
+ @hash = {key.to_sym => @hash} if key
17
21
  end
18
22
 
19
23
  def serialize
20
- fallback = -> { @_resource.to_json }
24
+ fallback = lambda do
25
+ require 'json'
26
+ JSON.dump(@hash)
27
+ end
21
28
  case Alba.backend
22
29
  when :oj
23
30
  begin
24
31
  require 'oj'
25
- -> { Oj.dump(@_resource) }
32
+ -> { Oj.dump(@hash, mode: :strict) }
26
33
  rescue LoadError
27
34
  fallback
28
35
  end
@@ -1,3 +1,5 @@
1
+ require 'alba/serializer'
2
+
1
3
  module Alba
2
4
  module Serializers
3
5
  # DefaultSerializer class is used when a user doesn't specify serializer opt.
@@ -1,3 +1,3 @@
1
1
  module Alba
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '0.7.0'.freeze
3
3
  end
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.2.0
4
+ version: 0.7.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-07-25 00:00:00.000000000 Z
11
+ date: 2020-07-31 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Fast and flexible JSON serializer
14
14
  email:
@@ -34,6 +34,7 @@ files:
34
34
  - lib/alba/many.rb
35
35
  - lib/alba/one.rb
36
36
  - lib/alba/resource.rb
37
+ - lib/alba/resources/default_resource.rb
37
38
  - lib/alba/serializer.rb
38
39
  - lib/alba/serializers/default_serializer.rb
39
40
  - lib/alba/version.rb