ember_data_active_model_parser 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 31076fab33df0652b49cf8644852ed956e01eefe
4
+ data.tar.gz: b6899da4c8032f5ff839d015c940d6ad0b229dad
5
+ SHA512:
6
+ metadata.gz: 3f99b3e115f000e221f71e6563a2ce51f6cdddfc79ce1e961f5a9f0bfe612fe67bce76f6525f31fe555de267a84d283ca6fd59d79feb793bab446b18909b2efa
7
+ data.tar.gz: 052262df9b34f76a0ed2e38b21ecb4514f5eeadaa416f0470ed5154ebe4ca0ac55b0d6f20bdbd2b845a87ceee08f0ebd117015c13d397b07c588cdf46ef124ad
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Valentin Mihov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # EmberDataActiveModelParser
2
+
3
+ This is a middleware for [Her](http://her-rb.org/) which makes it possible to consume API endpoints used by ember-data's [ActiveModelAdapter](http://emberjs.com/api/data/classes/DS.ActiveModelAdapter.html). You can read more about the data format in the ember-data's [docs](http://emberjs.com/api/data/classes/DS.ActiveModelAdapter.html)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'ember_data_active_model_parser'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install ember_data_active_model_parser
18
+
19
+ ## Usage
20
+
21
+ The parser expects that all your serializers are embedding the ids of the associations like this:
22
+
23
+ ```ruby
24
+ class ProjectSerializer < ActiveModel::Serializer
25
+ embed :ids, embed_in_root: true
26
+
27
+ attributes :id, :name
28
+
29
+ has_many :tasks
30
+ end
31
+
32
+ class TaskSerializer < ActiveModel::Serializer
33
+ embed :ids, embed_in_root: true
34
+
35
+ attributes :id, :name, :completed
36
+ end
37
+ ```
38
+
39
+ also you need to specify that active_model_serializers format in the Her models:
40
+
41
+ ```ruby
42
+ class Project
43
+ include Her::Model
44
+
45
+ parse_root_in_json true, format: :active_model_serializers
46
+
47
+ has_many :tasks
48
+ end
49
+
50
+ class Task
51
+ include Her::Model
52
+
53
+ parse_root_in_json true, format: :active_model_serializers
54
+
55
+ belongs_to :project
56
+ end
57
+ ```
58
+
59
+ In order to tell Her to use the serializer you need to replace the default JSON parser with it in an initializer (ex. config/initializers/her.rb):
60
+
61
+ ```ruby
62
+ Her::API.setup url: "http://localhost:3000" do |c|
63
+ # Request
64
+ c.use Faraday::Request::UrlEncoded
65
+
66
+ # Response
67
+ c.use EmberDataActiveModelParser::Middleware
68
+
69
+ # Adapter
70
+ c.use Faraday::Adapter::NetHttp
71
+ end
72
+ ```
73
+
74
+ ## Circular dependencies
75
+
76
+ Be careful when defining your serializers not to fall into a circular dependency problems. For example including the project_id in the tasks:
77
+
78
+ ```ruby
79
+ class ProjectSerializer < ActiveModel::Serializer
80
+ embed :ids, embed_in_root: true
81
+
82
+ attributes :id, :name
83
+
84
+ has_many :tasks
85
+ end
86
+
87
+ class TaskSerializer < ActiveModel::Serializer
88
+ embed :ids, embed_in_root: true
89
+
90
+ attributes :id, :name, :completed
91
+
92
+ # This is going to cause SystemStackError in her, because of the circular dependency between
93
+ # the models
94
+ attributes :project_id
95
+ end
96
+ ```
97
+
98
+ # Example projects
99
+
100
+ You can see some example probjects here:
101
+
102
+ * A Rails API with EmberJS as frontend for projects and tasks: [ember_rails_api_example](https://github.com/valo/ember_rails_api_example)
103
+ * A Rails app which uses Her as ORM to consume data from the example project above: [ember_rails_api_consumer](https://github.com/valo/ember_rails_api_consumer)
104
+
105
+ ## Contributing
106
+
107
+ 1. Fork it ( https://github.com/valo/ember_data_active_model_parser/fork )
108
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
109
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
110
+ 4. Push to the branch (`git push origin my-new-feature`)
111
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ember_data_active_model_parser/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ember_data_active_model_parser"
8
+ spec.version = EmberDataActiveModelParser::VERSION
9
+ spec.authors = ["Valentin Mihov"]
10
+ spec.email = ["valentin.mihov@gmail.com"]
11
+ spec.summary = %q{A parser for Her compatible with ember-data's active_model_serializers format}
12
+ spec.description = %q{A parser that enables Her to consume data exposed through active_model_serializers and compatible with the ember-data format}
13
+ spec.homepage = "https://github.com/valo/ember_data_active_model_parser"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "her"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ end
@@ -0,0 +1,19 @@
1
+ require "ember_data_active_model_parser/version"
2
+ require "ember_data_active_model_parser/embed_associations"
3
+ require "faraday"
4
+
5
+ module EmberDataActiveModelParser
6
+ class Middleware < Faraday::Response::Middleware
7
+ def parse(body)
8
+ json = MultiJson.load(body, symbolize_keys: true)
9
+
10
+ EmbedAssociations.new(json).call
11
+ end
12
+
13
+ def on_complete(env)
14
+ env[:body] = {
15
+ data: parse(env[:body])
16
+ }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,63 @@
1
+ require "active_support/inflector"
2
+
3
+ module EmberDataActiveModelParser
4
+ class EmbedAssociations
5
+ def initialize(root_json)
6
+ @root_json = root_json
7
+ end
8
+
9
+ def call
10
+ root_json.each do |key, value|
11
+ walk(value)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :root_json
18
+
19
+ def walk(object)
20
+ case object
21
+ when Array
22
+ object.each { |element| walk(element) }
23
+ when Hash
24
+ walk_hash(object)
25
+ end
26
+ end
27
+
28
+ def walk_hash(hash)
29
+ hash.keys.each do |key|
30
+ if association_ids_key(key, hash[key])
31
+ handle_association_ids(hash, hash.delete(key), association_name(key))
32
+ end
33
+ end
34
+ end
35
+
36
+ def handle_association_ids(hash, association_ids, association_name)
37
+ case association_ids
38
+ when Array
39
+ hash[association_name.pluralize.to_sym] = {
40
+ association_name.pluralize.to_sym => association_ids.map { |association_id|
41
+ association_array(association_name).find { |association_item| association_item[:id] == association_id }
42
+ }
43
+ }
44
+ when Fixnum
45
+ hash[association_name.to_sym] = {
46
+ association_name.to_sym => association_array(association_name).find { |association_item| association_item[:id] == association_ids }
47
+ }
48
+ end
49
+ end
50
+
51
+ def association_ids_key(key, value)
52
+ key.to_s =~ /(.+)_id(s?)$/ && association_array(association_name(key)) && (value.is_a?(Array) || value.is_a?(Fixnum))
53
+ end
54
+
55
+ def association_name(key)
56
+ key[/^(.+)_id(s?)$/, 1]
57
+ end
58
+
59
+ def association_array(association_name)
60
+ root_json[association_name.pluralize.to_sym]
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module EmberDataActiveModelParser
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,173 @@
1
+ require 'ember_data_active_model_parser'
2
+
3
+ describe EmberDataActiveModelParser::EmbedAssociations do
4
+ describe "#call" do
5
+ context "with an object with some associations" do
6
+ let(:tasks) do
7
+ [{
8
+ id: 1,
9
+ name: "Milk",
10
+ },
11
+ {
12
+ id: 2,
13
+ name: "Bread"
14
+ },
15
+ {
16
+ id: 3,
17
+ name: "Butter"
18
+ }]
19
+ end
20
+
21
+ let(:json) do
22
+ {
23
+ project: { id: 1, name: "Shop list", task_ids: [1,2,3] },
24
+ tasks: tasks
25
+ }
26
+ end
27
+ let(:expected_json) do
28
+ {
29
+ project: { id: 1, name: "Shop list", tasks: { tasks: tasks } },
30
+ tasks: tasks
31
+ }
32
+ end
33
+ let(:embed_associations) { EmberDataActiveModelParser::EmbedAssociations.new(json) }
34
+
35
+ it "embeds the objects from the root to the proper parents" do
36
+ expect(embed_associations.call).to eq(expected_json)
37
+ end
38
+ end
39
+
40
+ context "with an array of objects with some associations" do
41
+ let(:tasks) do
42
+ [{
43
+ id: 1,
44
+ name: "Milk",
45
+ project_id: projects[0][:id]
46
+ },
47
+ {
48
+ id: 2,
49
+ name: "Bread",
50
+ project_id: projects[0][:id]
51
+ },
52
+ {
53
+ id: 3,
54
+ name: "Butter",
55
+ project_id: projects[1][:id]
56
+ }]
57
+ end
58
+
59
+ let(:projects) do
60
+ [{
61
+ id: 1,
62
+ name: "Shop list",
63
+ task_ids: [1,2]
64
+ }, {
65
+ id: 2,
66
+ name: "Other Shop list",
67
+ task_ids: [3]
68
+ }]
69
+ end
70
+
71
+ let(:json) do
72
+ {
73
+ projects: projects,
74
+ tasks: tasks
75
+ }
76
+ end
77
+
78
+ let(:expected_tasks) do
79
+ [{
80
+ id: 1,
81
+ name: "Milk",
82
+ project: { project: projects[0] }
83
+ },
84
+ {
85
+ id: 2,
86
+ name: "Bread",
87
+ project: { project: projects[0] }
88
+ },
89
+ {
90
+ id: 3,
91
+ name: "Butter",
92
+ project: { project: projects[1] }
93
+ }]
94
+ end
95
+
96
+ let(:expected_projects) do
97
+ [{ id: 1, name: "Shop list", tasks: { tasks: expected_tasks[0, 2] } }, { id: 2, name: "Other Shop list", tasks: { tasks: expected_tasks[2, 3] } }]
98
+ end
99
+
100
+ let(:expected_json) do
101
+ {
102
+ projects: expected_projects,
103
+ tasks: expected_tasks
104
+ }
105
+ end
106
+ let(:embed_associations) { EmberDataActiveModelParser::EmbedAssociations.new(json) }
107
+
108
+ it "embeds the objects from the root to the proper parents" do
109
+ expect(embed_associations.call).to eq(expected_json)
110
+ end
111
+ end
112
+
113
+
114
+ context "with an object with some associations that have associations" do
115
+ let(:tasks) do
116
+ [{
117
+ id: 1,
118
+ name: "Milk",
119
+ author_id: 1
120
+ },
121
+ {
122
+ id: 2,
123
+ name: "Bread",
124
+ author_id: 2
125
+ }]
126
+ end
127
+
128
+ let(:expected_tasks) do
129
+ [{
130
+ id: 1,
131
+ name: "Milk",
132
+ author: { author: authors[0] }
133
+ },
134
+ {
135
+ id: 2,
136
+ name: "Bread",
137
+ author: { author: authors[1] }
138
+ }]
139
+ end
140
+
141
+ let(:authors) do
142
+ [{
143
+ id: 1,
144
+ name: "Mom"
145
+ },
146
+ {
147
+ id:2,
148
+ name: "Dad"
149
+ }]
150
+ end
151
+
152
+ let(:json) do
153
+ {
154
+ project: { id: 1, name: "Shop list", task_ids: [1,2] },
155
+ tasks: tasks,
156
+ authors: authors
157
+ }
158
+ end
159
+ let(:expected_json) do
160
+ {
161
+ project: { id: 1, name: "Shop list", tasks: { tasks: expected_tasks } },
162
+ tasks: expected_tasks,
163
+ authors: authors
164
+ }
165
+ end
166
+ let(:embed_associations) { EmberDataActiveModelParser::EmbedAssociations.new(json) }
167
+
168
+ it "embeds the objects from the root to the proper parents" do
169
+ expect(embed_associations.call).to eq(expected_json)
170
+ end
171
+ end
172
+ end
173
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ember_data_active_model_parser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Valentin Mihov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: her
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
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A parser that enables Her to consume data exposed through active_model_serializers
70
+ and compatible with the ember-data format
71
+ email:
72
+ - valentin.mihov@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - ember_data_active_model_parser.gemspec
83
+ - lib/ember_data_active_model_parser.rb
84
+ - lib/ember_data_active_model_parser/embed_associations.rb
85
+ - lib/ember_data_active_model_parser/version.rb
86
+ - spec/embed_associations_spec.rb
87
+ homepage: https://github.com/valo/ember_data_active_model_parser
88
+ licenses:
89
+ - MIT
90
+ metadata: {}
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 2.2.2
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: A parser for Her compatible with ember-data's active_model_serializers format
111
+ test_files:
112
+ - spec/embed_associations_spec.rb