jsonapi_mapper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: '039bcb95b5c5b71d03c25ead00660671ad9a2db2'
4
+ data.tar.gz: bc0abb1fe5a9dd7b119367e5b91a0c1480e4e2ca
5
+ SHA512:
6
+ metadata.gz: 55ccb1660bcd748ddea0cb153e1b3342be87fbdee5b3a0e793b1e3a50b85e548c69f81bcedd8a893710fdb3342ef938782d46e8266b0cb9ce9255c8c1f74c917
7
+ data.tar.gz: a84cf5543ad7f79b3b02e8361139f263b1f7ea949971fb75c4bea93a14bf345fed0b0b997e2ea6ee46db3a4310769245dccbaf082be1ec891db9987109eb1a74
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.swp
11
+ *.swo
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler -v 1.15.4
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in jsonapi_mapper.gemspec
6
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 nubis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,152 @@
1
+ # JsonapiMapper
2
+
3
+ Sanitizes a jsonapi Document and maps it to ActiveRecord, creating or updating as needed.
4
+ - Prevents assiginging unexpected attributes on your records.
5
+ - Prevents unscoped queries when creating/updating records.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'jsonapi_mapper'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install jsonapi_mapper
22
+
23
+ ## Usage
24
+
25
+ See the specs directory for more examples.
26
+
27
+ ```ruby
28
+ class Person < ActiveRecord::Base
29
+ belongs_to :parent, class_name: 'Person'
30
+ has_many :children, class_name: 'Person', foreign_key: 'parent_id'
31
+ belongs_to :pet, class_name: 'PetDog'
32
+ end
33
+
34
+ class PetDog < ActiveRecord::Base
35
+ has_one :person, foreign_key: 'pet_id'
36
+ end
37
+
38
+ # This document should create a person and several associations.
39
+ # Notice how these not-persisted resources can be referenced using
40
+ # an internal id, which starts with @
41
+ # The local @ ids shall be replaced with proper server assigned ids
42
+ # once the resources are persisted.
43
+ document = {
44
+ data: {
45
+ type: 'people',
46
+ attributes: { name: 'ian', admin: true },
47
+ relationships: {
48
+ pet: { data: { type: 'pet_dogs', id: '@1' }},
49
+ parent: { data: { type: 'people', id: '@1' }},
50
+ children: { data: [
51
+ { type: 'people', id: '@2' },
52
+ { type: 'people', id: '@3' },
53
+ ]},
54
+ }
55
+ },
56
+ included: [
57
+ { type: 'people', id: '@1', attributes: { name: 'ana', admin: true } },
58
+ { type: 'people', id: '@2', attributes: { name: 'bob', admin: true } },
59
+ { type: 'people', id: '@3', attributes: { name: 'zoe', admin: true } },
60
+ { type: 'pet_dogs', id: '@1', attributes: { name: 'ace', age: 11 } }
61
+ ]
62
+ }
63
+
64
+ # The mapper whitelists which types should be expected from the
65
+ # jsonapi document. It also whitelists attributes and relationship names.
66
+ # The last item of the attributes list is a Hash to be used as 'scope'
67
+ # when attempting to fetch and/or modify any resource.
68
+ mapper = JsonapiMapper.doc(document,
69
+ people: [:name, :pet, :parent, :children, country: 'argentina'],
70
+ pet_dogs: [:name, country: 'argentina']
71
+ )
72
+
73
+ person = mapper.data # This is the main document data as a new object
74
+ others = mapper.included # These are all the other resources.
75
+ mapper.save_all # Attempts to save both data and included.
76
+
77
+ # Four people have been created
78
+ Person.count.should == 4
79
+
80
+ # All of them from 'argentina' according to the provided scope.
81
+ Person.where(country: 'argentina').count.should == Person.count
82
+
83
+ # The 'admin' field was not set, because it wasn't in the mapper list.
84
+ Person.where(admin: true).count.should == 0
85
+
86
+ # This other document tries to update a bob's name and parent.
87
+ # And it also creates a new dow and assigns it as pet for 'bob' and 'ana'
88
+ other_document = {
89
+ data: {
90
+ type: 'people',
91
+ id: '1',
92
+ attributes: { name: 'rob' },
93
+ relationships: {
94
+ pet: { data: { type: 'pet_dogs', id: '@1' }},
95
+ parent: { data: { type: 'people', id: '2' }},
96
+ }
97
+ },
98
+ included: [
99
+ {
100
+ type: 'people',
101
+ id: ana.id,
102
+ relationships: {
103
+ pet: { data: { type: 'pet_dogs', id: '@1' }},
104
+ }
105
+ },
106
+ { type: 'pet_dogs', id: '@1', attributes: { name: 'ace' } }
107
+ ]
108
+ }
109
+
110
+ mapper = JsonapiMapper.doc other_document,
111
+ people: [:name, :pet, :parent, country: 'uruguay'],
112
+ pet_dogs: [:name, country: 'uruguay']
113
+
114
+ mapper.save_all
115
+
116
+ # Is dangerous to use unscoped queries
117
+ # For those rare occassions where you don't need them they can be disabled.
118
+ # The JsonapiMapper.doc_unsafe! method receives an argument with the names
119
+ # of all the types for which a scope is not required.
120
+ JsonapiMapper.doc_unsafe! document,
121
+ [:pet_dogs],
122
+ people: [:name, :pet, :parent, country: 'uruguay'],
123
+ pet_dogs: [:name]
124
+
125
+ # If you're needing to 'translate' between your jsonapi document names
126
+ # and your ActiveRecord class and column names, you can do it like so:
127
+ # Notice how the second hash has translations for type and attribute names.
128
+ mapper = JsonapiMapper.doc(document, {
129
+ persons: [:handle, :dog, :parental_figure, country: 'uruguay'],
130
+ pets: [:nickname, country: 'uruguay']
131
+ },
132
+ { types: { persons: Person, pets: PetDog },
133
+ attributes: {
134
+ persons: {handle: :name, dog: :pet, parental_figure: :parent},
135
+ pets: {nickname: :name},
136
+ }
137
+ }).save_all
138
+ ```
139
+
140
+ ## Development
141
+
142
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
143
+
144
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
145
+
146
+ ## Contributing
147
+
148
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/jsonapi_mapper.
149
+
150
+ ## License
151
+
152
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "jsonapi_mapper"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "jsonapi_mapper/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "jsonapi_mapper"
8
+ spec.version = JsonapiMapper::VERSION
9
+ spec.authors = ["nubis"]
10
+ spec.email = ["nb@bitex.la"]
11
+
12
+ spec.summary = %q{Sanitize and Map jsonapi documents straight into activemodels}
13
+ spec.description = %q{
14
+ Sanitizes a jsonapi Document and maps it to ActiveRecord,
15
+ creating or updating as needed.
16
+ Prevents mistakes when assigingng attributes or referring to
17
+ unscoped relationships.
18
+ }
19
+ spec.homepage = "https://github.com/bitex-la/jsonapi-mapper"
20
+ spec.license = "MIT"
21
+
22
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
23
+ f.match(%r{^(test|spec|features)/})
24
+ end
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_dependency "activesupport", '~> 4.2', '>= 4.2.0'
30
+ spec.add_dependency "activemodel",'~> 4.2', '>= 4.2.0'
31
+
32
+ spec.add_development_dependency "bundler", "~> 1.15"
33
+ spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency "rspec", "~> 3.0"
35
+ spec.add_development_dependency "activerecord", '~> 4.2', '>= 4.2.0'
36
+ spec.add_development_dependency "sqlite3", "~> 1.0", ">= 1.0.0"
37
+ spec.add_development_dependency "byebug", "~> 6.0", ">= 6.0.0"
38
+ end
@@ -0,0 +1,166 @@
1
+ require "jsonapi_mapper/version"
2
+
3
+ module JsonapiMapper
4
+ def self.doc(document, rules, renames = {})
5
+ DocumentMapper.new(document, [], rules, renames)
6
+ end
7
+
8
+ def self.doc_unsafe!(document, unscoped, rules, renames = {})
9
+ DocumentMapper.new(document, unscoped, rules, renames)
10
+ end
11
+
12
+ class RulesError < StandardError; end;
13
+
14
+ Id = Struct.new(:type, :raw)
15
+ Type = Struct.new(:name, :class, :rule)
16
+ Resource = Struct.new(:object, :relationships, :id)
17
+ Rule = Struct.new(:attributes, :scope)
18
+
19
+ class DocumentMapper
20
+ attr_accessor :document, :unscoped, :types, :renames, :resources,
21
+ :data, :included
22
+
23
+ def initialize(document, unscoped, rules, renames)
24
+ self.document = document.deep_symbolize_keys
25
+ self.renames = renames.deep_symbolize_keys
26
+ self.unscoped = unscoped.map(&:to_sym)
27
+ self.resources = {}
28
+
29
+ setup_types(rules)
30
+
31
+ main = if data = document[:data]
32
+ if data.is_a?(Array)
33
+ data.map{|r| build_resource(r) }.compact
34
+ else
35
+ build_resource(data)
36
+ end
37
+ end
38
+
39
+ rest = if included = document[:included]
40
+ included.map{|r| build_resource(r) }.compact
41
+ end
42
+
43
+ resources.each{|_,r| assign_relationships(r) }
44
+
45
+ self.data = main.is_a?(Array) ? main.map(&:object) : main.try(:object)
46
+ self.included = rest.try(:map, &:object)
47
+ end
48
+
49
+ def setup_types(rules)
50
+ self.types = {}
51
+ rules.each do |type_name, ruleset|
52
+ type_name = type_name.to_sym
53
+
54
+ attrs, scope = if ruleset.last.is_a?(Hash)
55
+ [ruleset[0..-2], ruleset.last]
56
+ else
57
+ unless unscoped.map(&:to_sym).include?(type_name)
58
+ raise RulesError.new("Missing Scope for #{type_name}")
59
+ end
60
+ [ruleset, {}]
61
+ end
62
+
63
+ unless attrs.all?{|v| v.is_a?(Symbol) || v.is_a?(String) }
64
+ raise RulesError.new('Attributes must be Strings or Symbols')
65
+ end
66
+
67
+ attrs = attrs.map(&:to_sym)
68
+ scope.symbolize_keys!
69
+
70
+ danger = scope.keys.to_set & attrs.map{|a| renamed(type_name, a) }.to_set
71
+ if danger.count > 0
72
+ raise RulesError.new("Don't let user set the scope: #{danger.to_a}")
73
+ end
74
+
75
+ cls = renames.fetch(:types, {})[type_name] ||
76
+ type_name.to_s.singularize.camelize.constantize
77
+
78
+ attrs.map{|a| renamed(type_name, a) }.each do |attr|
79
+ unless cls.new.respond_to?(attr)
80
+ raise NoMethodError.new("undefined method #{attr} for #{cls}")
81
+ end
82
+ end
83
+
84
+ types[type_name] = Type.new(type_name, cls, Rule.new(attrs, scope))
85
+ end
86
+ end
87
+
88
+ def build_resource(json)
89
+ return unless json.is_a? Hash
90
+ return unless json.fetch(:relationships, {}).is_a?(Hash)
91
+ return unless json.fetch(:attributes, {}).is_a?(Hash)
92
+ return unless type = types[json[:type].try(:to_sym)]
93
+
94
+ object = if json[:id].nil? || json[:id].to_s.starts_with?("@")
95
+ type.class.new.tap do |o|
96
+ type.rule.scope.each do |k,v|
97
+ o.send("#{k}=", v)
98
+ end
99
+ end
100
+ else
101
+ type.class.where(type.rule.scope).find(json[:id])
102
+ end
103
+
104
+ relationships = {}
105
+ json.fetch(:relationships, {}).each do |name, value|
106
+ next unless type.rule.attributes.include?(name)
107
+ relationships[renamed(type.name, name)] = if value[:data].is_a?(Array)
108
+ value[:data].map{|v| build_id(v) }
109
+ else
110
+ build_id(value[:data])
111
+ end
112
+ end
113
+
114
+ if attributes_to_be_set = json[:attributes]
115
+ type.rule.attributes.each do |name|
116
+ if value = attributes_to_be_set[name]
117
+ object.send("#{renamed(type.name, name)}=", value)
118
+ end
119
+ end
120
+ end
121
+
122
+ resource = Resource.new(object, relationships, build_id(json))
123
+ resources[resource.id] = resource
124
+ end
125
+
126
+ def build_id(json)
127
+ Id.new(json[:type].to_sym, json[:id])
128
+ end
129
+
130
+ def assign_relationships(resource)
131
+ resource.relationships.each do |name, ids|
132
+ if ids.is_a?(Array)
133
+ ids.each do |id|
134
+ next unless other = find_resource_object(id)
135
+ resource.object.send(name).push(other)
136
+ end
137
+ else
138
+ next unless other = find_resource_object(ids)
139
+ resource.object.send("#{name}=", other)
140
+ end
141
+ end
142
+ end
143
+
144
+ def find_resource_object(id)
145
+ return unless type = types[id.type]
146
+
147
+ resources[id].try(:object) ||
148
+ type.class.where(type.rule.scope).find(id.raw) or
149
+ raise ActiveRecord::RecordNotFound
150
+ .new("Couldn't find #{id.type} with id=#{id.raw}")
151
+ end
152
+
153
+ def renamed(type, attr)
154
+ renames.fetch(:attributes, {}).fetch(type, {}).fetch(attr, attr)
155
+ end
156
+
157
+ def save_all
158
+ data.is_a?(Array) ? data.each(&:save) : data.try(:save)
159
+ included.try(:each, &:save)
160
+ end
161
+
162
+ def collection?
163
+ data.is_a?(Array)
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,3 @@
1
+ module JsonapiMapper
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,200 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jsonapi_mapper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - nubis
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-11-27 00:00:00.000000000 Z
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: '4.2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 4.2.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '4.2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 4.2.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: activemodel
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '4.2'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 4.2.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '4.2'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 4.2.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: bundler
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '1.15'
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '1.15'
67
+ - !ruby/object:Gem::Dependency
68
+ name: rake
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '10.0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '10.0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: rspec
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '3.0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '3.0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: activerecord
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '4.2'
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 4.2.0
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '4.2'
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: 4.2.0
115
+ - !ruby/object:Gem::Dependency
116
+ name: sqlite3
117
+ requirement: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - "~>"
120
+ - !ruby/object:Gem::Version
121
+ version: '1.0'
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 1.0.0
125
+ type: :development
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.0'
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 1.0.0
135
+ - !ruby/object:Gem::Dependency
136
+ name: byebug
137
+ requirement: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - "~>"
140
+ - !ruby/object:Gem::Version
141
+ version: '6.0'
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 6.0.0
145
+ type: :development
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '6.0'
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: 6.0.0
155
+ description: "\n Sanitizes a jsonapi Document and maps it to ActiveRecord,\n creating
156
+ or updating as needed.\n Prevents mistakes when assigingng attributes or referring
157
+ to \n unscoped relationships.\n "
158
+ email:
159
+ - nb@bitex.la
160
+ executables: []
161
+ extensions: []
162
+ extra_rdoc_files: []
163
+ files:
164
+ - ".gitignore"
165
+ - ".rspec"
166
+ - ".travis.yml"
167
+ - Gemfile
168
+ - LICENSE.txt
169
+ - README.md
170
+ - Rakefile
171
+ - bin/console
172
+ - bin/setup
173
+ - jsonapi_mapper.gemspec
174
+ - lib/jsonapi_mapper.rb
175
+ - lib/jsonapi_mapper/version.rb
176
+ homepage: https://github.com/bitex-la/jsonapi-mapper
177
+ licenses:
178
+ - MIT
179
+ metadata: {}
180
+ post_install_message:
181
+ rdoc_options: []
182
+ require_paths:
183
+ - lib
184
+ required_ruby_version: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ required_rubygems_version: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: '0'
194
+ requirements: []
195
+ rubyforge_project:
196
+ rubygems_version: 2.6.11
197
+ signing_key:
198
+ specification_version: 4
199
+ summary: Sanitize and Map jsonapi documents straight into activemodels
200
+ test_files: []