undo-serializer-active_model 0.0.4 → 0.1.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
  SHA1:
3
- metadata.gz: a8f6129e916df1177c739956b56adcfb3b1f337b
4
- data.tar.gz: 09f23cd4001f82babd417949d40dced4323e359e
3
+ metadata.gz: a295ea13f84f57828d1f8f160c46776e92cff623
4
+ data.tar.gz: 65880e189d3907d9a4ff5ca31fe3f9fca9156619
5
5
  SHA512:
6
- metadata.gz: 4d219d7d0189d6eeb4bd05bc144e663c543aaeb902d1832545e7b0b4003a353a7514a24cf5d9fdc7417f39dfc57675bc68ea320d6cadf073c89373ccc4c7c034
7
- data.tar.gz: afda0a79e726b1656deaed0c48d73f6f6052d5414560c91d21a2f9804e20d7d574afa44c3b737bbfa6f7ea7fbba944bd6df5d3c4f8bea346db63bc1b24224e03
6
+ metadata.gz: d995320ec3063c1f92e11062ce5f75190f78ae98313ad6f8cb5eeef8a54ff7cc64621af57ec3048da98d4ad9353866503cacb024e047b53252a5124d335d26a2
7
+ data.tar.gz: 6d197310535c87d08e0f27564ee6b2be3fc4854b0fd5e6c3289250edcb5566cdb71cf1e92b7d4a557ebbf8f894adbf124cb3a989cdd8c9379c08c678244b72ac
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.1.0-p0
1
+ 2.1.1
data/Gemfile CHANGED
@@ -21,7 +21,6 @@ group :test, :development do
21
21
  gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
22
22
  gem 'factory_girl'
23
23
  gem 'faker'
24
- gem "active_model_serializers", "~> 0.8"
25
24
  end
26
25
 
27
26
  gemspec
data/README.md CHANGED
@@ -4,10 +4,9 @@ Undo
4
4
  [![Gemnasium Build Status](https://gemnasium.com/AlexParamonov/undo-serializer-active_model.png)](http://gemnasium.com/AlexParamonov/undo-serializer-active_model)
5
5
  [![Coverage Status](https://coveralls.io/repos/AlexParamonov/undo-serializer-active_model/badge.png?branch=master)](https://coveralls.io/r/AlexParamonov/undo-serializer-active_model?branch=master)
6
6
  [![Gem Version](https://badge.fury.io/rb/undo-serializer-active_model.png)](http://badge.fury.io/rb/undo-serializer-active_model)
7
+ [![Code Climate](https://codeclimate.com/github/AlexParamonov/undo-serializer-active_model.png)](https://codeclimate.com/github/AlexParamonov/undo-serializer-active_model)
7
8
 
8
- ActiveModel serializer for Undo gem.
9
-
10
- Designed to be used with `gem "active_model_serializers"`, but does not depends on it.
9
+ ActiveModel serializer for Undo gem. Does not require anything from Rails so is friendly to use with POROs.
11
10
 
12
11
  Contents
13
12
  ---------
@@ -33,16 +32,19 @@ Or install it yourself as:
33
32
 
34
33
  $ gem install undo-serializer-active_model
35
34
 
35
+ Most likely you'll install undo gem as well:
36
+
37
+ $ gem install undo
38
+
36
39
  Requirements
37
40
  ------------
38
41
  1. Ruby >= 1.9
39
- 1. `activesupport` (`active_model_serializers` depends on it)
40
42
 
41
43
  Usage
42
44
  ------------
43
45
 
44
46
  Gem is designed to be used with Undo gem.
45
- Add it in global config:
47
+ Customize Undo to use serializer in global configuration:
46
48
 
47
49
  ``` ruby
48
50
  Undo.configure do |config|
@@ -50,43 +52,36 @@ Undo.configure do |config|
50
52
  end
51
53
  ```
52
54
 
53
- Custom serializer could be provided to the adapter:
55
+ Custom primary_key set, find_or_initialize and persist `Proc`s could be provided to the adapter:
54
56
  ``` ruby
55
57
  Undo.configure do |config|
56
- config.serializer =
57
- Undo::Serializer::ActiveModel.new serializer: ->(object) { "#{object.class.name}UndoSerializer".constantize.new(object) }
58
+ config.serializer = Undo::Serializer::ActiveModel.new(
59
+ primary_key: [:id, :status],
60
+ find_or_initialize: ->(object_class, pk_attributes) { object_class.find_or_initialize_by pk_attributes },
61
+ serialize_attributes: ->(object) { object.serializable_hash },
62
+ persist: ->(object) { object.save! },
63
+ )
58
64
  end
59
65
  ```
60
66
 
61
- Or it may be initialized by serializer instance:
62
- ``` ruby
63
- Undo.configure do |config|
64
- config.serializer =
65
- Undo::Serializer::ActiveModel.new CustomSerializer.new
66
- end
67
- ```
67
+ For ActiveRecord Undo uses reasonable defaults, so most of the time it is not needed to overwrite them.
68
+ It should work with most Virtus objects as well.
68
69
 
69
- As usual any Undo configuration may be set in place on wrap and restore:
70
+ As usual any Undo configuration may be set in place on store, wrap and restore:
70
71
  ``` ruby
71
- Undo.wrap user, serializer: Undo::Serializer::ActiveModel.new
72
- Undo.restore uuid, serializer: Undo::Serializer::ActiveModel.new
73
- ```
74
-
75
- In place using the specific serializer from `gem "active_model_serializers"`:
76
- ``` ruby
77
- Undo.wrap user, serializer: Undo::Serializer::ActiveModel.new(UserSerializer.new(user))
72
+ Undo.store user, serializer: Undo::Serializer::ActiveRecord.new(primary_key: :uuid)
73
+ Undo.restore uuid, primary_key: :uuid, persist: ->(object) { object.write_to_disk! }
78
74
  ```
79
75
 
80
76
  ### Associations
81
77
 
82
- It is required to set `somethig___association_class_name` as `key` in `active_model_serializer`:
78
+ Add `include` option to serialize the association
83
79
  ``` ruby
84
- class UserSerializer < ActiveModel::Serializer
85
- attributes *User.attribute_names.map(&:to_sym)
86
- has_many :roles, key: :has_many___roles
87
- end
80
+ uuid = Undo.store post, include: comments
81
+ Undo.restore uuid
88
82
  ```
89
83
 
84
+ Will restore post with related comments.
90
85
 
91
86
  Contacts
92
87
  -------------
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.1.0
data/gemfiles/3.0.gemfile CHANGED
@@ -25,7 +25,6 @@ group :test, :development do
25
25
  gem "sqlite3", :platform=>[:ruby, :mswin, :mingw]
26
26
  gem "factory_girl"
27
27
  gem "faker"
28
- gem "active_model_serializers", "~> 0.8"
29
28
  end
30
29
 
31
30
  gemspec :path=>".././"
data/gemfiles/3.1.gemfile CHANGED
@@ -25,7 +25,6 @@ group :test, :development do
25
25
  gem "sqlite3", :platform=>[:ruby, :mswin, :mingw]
26
26
  gem "factory_girl"
27
27
  gem "faker"
28
- gem "active_model_serializers", "~> 0.8"
29
28
  end
30
29
 
31
30
  gemspec :path=>".././"
data/gemfiles/3.2.gemfile CHANGED
@@ -25,7 +25,6 @@ group :test, :development do
25
25
  gem "sqlite3", :platform=>[:ruby, :mswin, :mingw]
26
26
  gem "factory_girl"
27
27
  gem "faker"
28
- gem "active_model_serializers", "~> 0.8"
29
28
  end
30
29
 
31
30
  gemspec :path=>".././"
data/gemfiles/4.0.gemfile CHANGED
@@ -25,7 +25,6 @@ group :test, :development do
25
25
  gem "sqlite3", :platform=>[:ruby, :mswin, :mingw]
26
26
  gem "factory_girl"
27
27
  gem "faker"
28
- gem "active_model_serializers", "~> 0.8"
29
28
  end
30
29
 
31
30
  gemspec :path=>".././"
data/gemfiles/4.1.gemfile CHANGED
@@ -25,7 +25,6 @@ group :test, :development do
25
25
  gem "sqlite3", :platform=>[:ruby, :mswin, :mingw]
26
26
  gem "factory_girl"
27
27
  gem "faker"
28
- gem "active_model_serializers", "~> 0.8"
29
28
  end
30
29
 
31
30
  gemspec :path=>".././"
@@ -1,65 +1,124 @@
1
- require "active_support"
2
-
3
1
  module Undo
4
2
  module Serializer
5
3
  class ActiveModel
6
- def initialize(*args)
7
- options = args.extract_options!
8
- @serializer = args.first
9
- @serializer_source = options.fetch :serializer,
10
- ->(object) { object.active_model_serializer.new object }
4
+ def initialize(options = {})
5
+ load_options options
11
6
  end
12
7
 
13
- def serialize(object)
14
- serializer(object).as_json
8
+ def serialize(object, options = {})
9
+ return object.map do |record|
10
+ serialize record, options
11
+ end if array? object
12
+
13
+ load_options options
14
+
15
+ attributes = serialize_attributes(object) || {}
16
+ associations = {}
17
+ Array(options[:include]).map do |association|
18
+ associations[association] = serialize(object.public_send association)
19
+ end
20
+ pk_attributes = symbolize_keys(attributes).select do |attribute|
21
+ primary_key_fields.include? attribute
22
+ end
23
+
24
+ {
25
+ attributes: attributes,
26
+ associations: associations,
27
+ meta: {
28
+ pk_attributes: pk_attributes,
29
+ class_name: object.class.name,
30
+ }
31
+ }
15
32
  end
16
33
 
17
- def deserialize(hash)
18
- object_handler, data = hash.first
19
- return unless data.is_a? Hash
20
- data.stringify_keys!
34
+ def deserialize(object, options = {})
35
+ return object.map do |record|
36
+ deserialize record
37
+ end if array? object
38
+
39
+ load_options options
21
40
 
22
- ActiveRecord::Base.transaction do
23
- initialize_object(object_handler, data).tap do |object|
24
- data.each do |field, value|
25
- next if "id" == field && object.persisted?
41
+ hash = symbolize_keys object
42
+ object_meta = hash.fetch :meta
43
+ associations = hash.fetch :associations
44
+ attributes = hash.fetch :attributes
26
45
 
27
- case field
28
- when /___(.*)/ then deserialize_association object, $1, value
29
- else deserialize_field object, field, value
30
- end
46
+ with_transaction do
47
+ initialize_object(object_meta).tap do |object|
48
+ attributes.each do |field, value|
49
+ deserialize_field object, field, value
31
50
  end
32
51
 
33
- object.save!
52
+ # QUESTION: Set associations? object.association_name = deserialize association ?
53
+ associations.each do |(association_name, association)|
54
+ deserialize association
55
+ end
56
+
57
+ persist object
34
58
  end
35
59
  end
36
-
37
60
  end
38
61
 
39
62
  private
40
- attr_reader :serializer_source
63
+ attr_reader :serialize_attributes_source,
64
+ :initialize_object_source,
65
+ :persist_object_source
41
66
 
42
- def serializer(object)
43
- @serializer ||= serializer_source.call object
67
+ def deserialize_field(object, field, value)
68
+ object.send "#{field}=", value # not public_send!
44
69
  end
45
70
 
46
- def deserialize_association(object, association, values)
47
- Array.wrap(values).each do |value|
48
- deserialize object.public_send(association) => value
71
+ def initialize_object(meta)
72
+ object_class = constantize meta.fetch(:class_name)
73
+ pk_attributes = meta.fetch :pk_attributes
74
+
75
+ find_or_initialize object_class, pk_attributes
76
+ end
77
+
78
+ def with_transaction(&block)
79
+ if defined? ActiveRecord
80
+ ActiveRecord::Base.transaction(&block)
81
+ else
82
+ block.call
49
83
  end
50
84
  end
51
85
 
52
- def deserialize_field(object, field, value)
53
- object.send "#{field}=", value # not public_send!
86
+ def load_options(options)
87
+ @serialize_attributes_source = options.fetch :serialize_attributes, @serialize_attributes_source ||
88
+ ->(object) { object.attributes }
89
+
90
+ @initialize_object_source = options.fetch :find_or_initialize, @initialize_object_source ||
91
+ ->(object_class, pk_query) { object_class.respond_to?(:where) && object_class.where(pk_query).first || object_class.new(pk_query) }
92
+
93
+ @persist_object_source = options.fetch :persist, @persist_object_source ||
94
+ ->(object) { object.respond_to?(:save!) && object.save! }
95
+
96
+ @primary_key_fields = options.fetch :primary_key, @primary_key_fields || :id
54
97
  end
55
98
 
56
- def initialize_object(object_handler, data)
57
- id = data.fetch "id"
58
- relation = case object_handler
59
- when String, Symbol then object_handler.to_s.camelize.constantize
60
- else object_handler end
99
+ def primary_key_fields
100
+ Array(@primary_key_fields)
101
+ end
102
+
103
+ def serialize_attributes(*args); serialize_attributes_source.call(*args) end
104
+ def find_or_initialize(*args); initialize_object_source.call(*args) end
105
+ def persist(*args); persist_object_source.call(*args) end
106
+
107
+ def array?(object)
108
+ object.respond_to?(:map) && ! object.is_a?(Hash)
109
+ end
110
+ # ActiveSupport methods
111
+ def symbolize_keys(hash)
112
+ hash.each_with_object({}) do |(key, value), result|
113
+ new_key = key.is_a?(String) ? key.to_sym : key
114
+ new_value = value.is_a?(Hash) ? symbolize_keys(value) : value
115
+
116
+ result[new_key] = new_value
117
+ end
118
+ end
61
119
 
62
- relation.where(id: id).first || relation.new(id: id)
120
+ def constantize(class_name)
121
+ class_name.split('::').inject(Kernel) { |object, name| object = object.const_get(name); object }
63
122
  end
64
123
  end
65
124
  end
@@ -2,7 +2,6 @@ require "spec_helper"
2
2
  require "support/active_record"
3
3
  require "user"
4
4
  require "role"
5
- require "user_serializer"
6
5
 
7
6
  describe Undo::Serializer::ActiveModel do
8
7
  subject { described_class }
@@ -19,17 +18,19 @@ describe Undo::Serializer::ActiveModel do
19
18
  expect(restored_user).to be_persisted
20
19
  end
21
20
 
22
- it "restores object and associations" do
23
- roles = create_list :role, 3, user: user
24
- hash = serializer.serialize user
25
- user.delete
26
- Role.delete_all # HACK for ActiveRecord 3.0
21
+ describe "associations" do
22
+ it "restores provided associations" do
23
+ roles = create_list :role, 3, user: user
24
+ hash = serializer.serialize user, include: :roles
25
+ user.delete
26
+ Role.delete_all # HACK for ActiveRecord 3.0
27
27
 
28
- restored_user = serializer.deserialize hash
28
+ restored_user = serializer.deserialize hash
29
29
 
30
- restored_user.reload # HACK for ActiveRecord 3.0
31
- expect(restored_user).to eq user
32
- expect(restored_user.roles).to eq roles
30
+ restored_user.reload # HACK for ActiveRecord 3.0
31
+ expect(restored_user).to eq user
32
+ expect(restored_user.roles).to eq roles
33
+ end
33
34
  end
34
35
 
35
36
  it "reverts changes to object" do
@@ -43,9 +44,14 @@ describe Undo::Serializer::ActiveModel do
43
44
  expect(restored_user).to eq user.reload
44
45
  end
45
46
 
46
- it "detects default serializer for a model" do
47
- serializer = subject.new
48
- expect(UserSerializer).to receive(:new)
49
- serializer.serialize(user)
47
+ describe "array of objects" do
48
+ it "restores a collection" do
49
+ users = create_list :user, 3
50
+ array = serializer.serialize users, include: :roles
51
+ users.each &:delete
52
+
53
+ restored_users = serializer.deserialize array
54
+ expect(restored_users).to eq users
55
+ end
50
56
  end
51
57
  end
@@ -3,38 +3,70 @@ require "spec_helper"
3
3
  describe Undo::Serializer::ActiveModel do
4
4
  subject { described_class }
5
5
  let(:serializer) { subject.new }
6
- let(:object) { double :object }
7
- let(:am_serializer_method) { :as_json }
6
+ let(:object) { double :object, attributes: { id: 1, foo: "bar", bar: "baz", hello: "world" } }
7
+
8
+ describe "custom finder fields" do
9
+ it "uses finder fields to find the object" do
10
+ FooBarTestObject = Class.new
11
+ serializer = subject.new primary_key: [:foo, :bar]
12
+ allow(object).to receive(:class) { FooBarTestObject }
13
+
14
+ expect(FooBarTestObject).to receive(:new).with(foo: "bar", bar: "baz") { object.as_null_object }
15
+
16
+ hash = serializer.serialize object
17
+ serializer.deserialize hash
18
+ end
19
+ end
8
20
 
9
21
  describe "custom serializer" do
10
- it "uses provided serializer" do
11
- custom_serializer = double :custom_serializer
12
- serializer = subject.new custom_serializer
22
+ it "uses provided attribute serialization" do
23
+ attribute_serializer = double :attribute_serializer
24
+ serializer = subject.new serialize_attributes: attribute_serializer
13
25
 
14
- expect(custom_serializer).to receive am_serializer_method
26
+ expect(attribute_serializer).to receive(:call).with(object)
15
27
  serializer.serialize object
16
28
  end
17
29
 
18
- it "uses custom serializer source" do
19
- custom_serializer_source = double :custom_serializer_source
20
- custom_serializer = double :custom_serializer
21
- serializer = subject.new serializer: custom_serializer_source
30
+ it "uses provided find_or_initialize deserialization" do
31
+ deserializer = double :find_or_initialize_deserializer
32
+ serializer = subject.new find_or_initialize: deserializer
22
33
 
23
- expect(custom_serializer_source).to receive(:call).with(object) { custom_serializer }
24
- expect(custom_serializer).to receive am_serializer_method
25
- serializer.serialize object
34
+ hash = serializer.serialize object
35
+ expect(deserializer).to receive(:call).with(object.class, id: 1) { object.as_null_object }
36
+ serializer.deserialize hash
26
37
  end
27
38
 
28
- it "has lower priority than providing the serializer directly" do
29
- custom_serializer_source = double :custom_serializer_source
30
- custom_serializer = double :custom_serializer
39
+ it "uses provided way of persisting object" do
40
+ persister = double :persister
31
41
 
32
- serializer = subject.new custom_serializer, serializer: custom_serializer_source
42
+ deserializer = double :find_or_initialize_deserializer
43
+ allow(deserializer).to receive(:call) { object.as_null_object }
44
+ serializer = subject.new persist: persister, find_or_initialize: deserializer
33
45
 
34
- expect(custom_serializer_source).not_to receive(:call)
35
- expect(custom_serializer).to receive am_serializer_method
46
+ hash = serializer.serialize object
47
+ expect(persister).to receive(:call).with(object)
48
+ serializer.deserialize hash
49
+ end
50
+ end
36
51
 
37
- serializer.serialize object
52
+ describe "in place serializer options" do
53
+ specify "#serialize" do
54
+ attribute_serializer = double :attribute_serializer
55
+ serializer = subject.new
56
+
57
+ expect(attribute_serializer).to receive(:call).with(object)
58
+ serializer.serialize object,
59
+ serialize_attributes: attribute_serializer
60
+ end
61
+
62
+ specify "#deserialize" do
63
+ deserializer = double :find_or_initialize_deserializer
64
+ serializer = subject.new
65
+
66
+ hash = serializer.serialize object
67
+ expect(deserializer).to receive(:call).with(object.class, id: 1) { object.as_null_object }
68
+ serializer.deserialize hash,
69
+ find_or_initialize: deserializer
38
70
  end
39
71
  end
40
72
 
@@ -7,8 +7,8 @@ Gem::Specification.new do |spec|
7
7
  spec.version = IO.read("VERSION")
8
8
  spec.authors = ["Alexander Paramonov"]
9
9
  spec.email = ["alexander.n.paramonov@gmail.com"]
10
- spec.summary = %q{ActiveModel serializer for Undo gem.}
11
- spec.description = %q{ActiveModel serializer for Undo gem.}
10
+ spec.summary = %q{ActiveModel serializer for Undo gem. Does not require anything from Rails so is friendly to use with POROs.}
11
+ spec.description = %q{ActiveModel serializer for Undo gem. Does not require anything from Rails so is friendly to use with POROs.}
12
12
  spec.homepage = "http://github.com/AlexParamonov/undo-serializer-active_model"
13
13
  spec.license = "MIT"
14
14
 
@@ -17,6 +17,5 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_dependency "activesupport"
21
20
  spec.add_development_dependency 'bundler', '~> 1.0'
22
21
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: undo-serializer-active_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Paramonov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-22 00:00:00.000000000 Z
11
+ date: 2014-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: activesupport
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: bundler
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -38,7 +24,8 @@ dependencies:
38
24
  - - "~>"
39
25
  - !ruby/object:Gem::Version
40
26
  version: '1.0'
41
- description: ActiveModel serializer for Undo gem.
27
+ description: ActiveModel serializer for Undo gem. Does not require anything from Rails
28
+ so is friendly to use with POROs.
42
29
  email:
43
30
  - alexander.n.paramonov@gmail.com
44
31
  executables: []
@@ -68,7 +55,6 @@ files:
68
55
  - spec/support/active_record/role.rb
69
56
  - spec/support/active_record/schema.rb
70
57
  - spec/support/active_record/user.rb
71
- - spec/support/active_record/user_serializer.rb
72
58
  - spec/support/ci_helper.rb
73
59
  - spec/support/factories.rb
74
60
  - spec/undo/serializer/active_model_integration_spec.rb
@@ -94,19 +80,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
80
  version: '0'
95
81
  requirements: []
96
82
  rubyforge_project:
97
- rubygems_version: 2.2.2
83
+ rubygems_version: 2.1.11
98
84
  signing_key:
99
85
  specification_version: 4
100
- summary: ActiveModel serializer for Undo gem.
86
+ summary: ActiveModel serializer for Undo gem. Does not require anything from Rails
87
+ so is friendly to use with POROs.
101
88
  test_files:
102
89
  - spec/spec_helper.rb
103
90
  - spec/support/active_record.rb
104
91
  - spec/support/active_record/role.rb
105
92
  - spec/support/active_record/schema.rb
106
93
  - spec/support/active_record/user.rb
107
- - spec/support/active_record/user_serializer.rb
108
94
  - spec/support/ci_helper.rb
109
95
  - spec/support/factories.rb
110
96
  - spec/undo/serializer/active_model_integration_spec.rb
111
97
  - spec/undo/serializer/active_model_spec.rb
112
- has_rdoc:
@@ -1,6 +0,0 @@
1
- require "active_model_serializers"
2
-
3
- class UserSerializer < ActiveModel::Serializer
4
- attributes :id, :name, :email
5
- has_many :roles, key: :has_many___roles
6
- end