cartograph 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 75a2908b56243cc37194669f69b38f4b98b98674
4
+ data.tar.gz: d6ef9fc6b4ada540498ba187594fdff5234767aa
5
+ SHA512:
6
+ metadata.gz: 46424d9ba2555a11ea4acac0ad660259b5b46d47b9a1da40226c9dd8695cb7df22a6f82d4c02c2c9a5339b15290c5ffacaec91e6329c1d210b2d0939dd71a8ea
7
+ data.tar.gz: 4bc57fb275ea7f6f3f349af9e08f34ca20c9d302b7612ae1575c1d942b86d05dc6a624170df72bed91b4d0d334d4b933be59df0dffb023d8a6fe6058928db307
@@ -0,0 +1,23 @@
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
23
+ .pairs
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.1
4
+ - 2.0.0
@@ -0,0 +1,11 @@
1
+ Cartograph Changelog
2
+ ====================
3
+
4
+ ### master
5
+
6
+ ### [v1.0.0][v1.0.0] (September 7, 2017)
7
+
8
+ * Added support for dry-struct
9
+ ([#3](https://github.com/kyrylo/cartograph/pull/3))
10
+
11
+ [v1.0.0]: https://github.com/kyrylo/cartograph/releases/tag/v1.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cartograph.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Robert Ross
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.
@@ -0,0 +1,211 @@
1
+ # Cartograph
2
+
3
+ A Serialization / Deserialization library.
4
+
5
+ [![Build Status](https://travis-ci.org/kyrylo/cartograph.svg?branch=master)](https://travis-ci.org/kyrylo/cartograph)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'cartograph'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ ## Usage
18
+
19
+ Cartograph makes it easy to generate and convert JSON. It's intention is to be used for API clients.
20
+
21
+ For example, if you have an object that you would like to convert to JSON for a create request to an API. You would have something similar to this:
22
+
23
+ ```ruby
24
+ class UserMapping
25
+ include Cartograph::DSL
26
+
27
+ cartograph do
28
+ mapping User # The object we're mapping
29
+
30
+ property :name, :email, scopes: [:create, :update]
31
+ property :id, scopes: :read
32
+ end
33
+ end
34
+
35
+ user = User.new(name: 'Bobby Tables')
36
+ json_for_create = UserMapping.representation_for(:create, user)
37
+ ```
38
+
39
+ ### Rendering Objects or Collections as Hashes
40
+
41
+ ```ruby
42
+ user = User.new(name: 'PB Jelly')
43
+ users = [user]
44
+
45
+ hash = UserMapping.hash_for(:read, user)
46
+ hash_collection = UserMapping.hash_collection_for(:read, user)
47
+ ```
48
+
49
+ ### Rendering Collections as JSON
50
+
51
+ ```ruby
52
+ user = User.new(name: 'Bobby Tables')
53
+ users = Array.new(10, user)
54
+
55
+ json = UserMapping.represent_collection_for(:read, users)
56
+ ```
57
+
58
+ ---
59
+
60
+ Some API's will give you the created resource back as JSON as well on a successful create. For that, you may do something like this:
61
+
62
+ ```ruby
63
+ response = HTTPClient.post("http://something.com/api/users", body: json_for_create)
64
+ created_user = UserMapping.extract_single(response.body, :read)
65
+ ```
66
+
67
+ Most API's will have a way of retrieving an entire resource collection. For this you can instruct Cartograph to convert a collection.
68
+
69
+ ```ruby
70
+ response = HTTPClient.get("http://something.com/api/users")
71
+ users = UserMapping.extract_collection(response.body, :read)
72
+ # => [ User, User, User ]
73
+ ```
74
+
75
+ ### Getting Harder
76
+
77
+ Sometimes resources will nest other properties under a key. Cartograph can handle this as well.
78
+
79
+ ```ruby
80
+ class UserMapping
81
+ include Cartograph::DSL
82
+
83
+ cartograph do
84
+ mapping User # The object we're mapping
85
+
86
+ property :name, scopes: [:read]
87
+
88
+ property :comments do
89
+ mapping Comment # The nested object we're mapping
90
+
91
+ property :text, scopes: [:read]
92
+ property :author, scopes: [:read]
93
+ end
94
+ end
95
+ end
96
+ ```
97
+
98
+ Just like the previous examples, when you serialize this. It will include the comment block for the scope defined.
99
+
100
+ ### Root Keys
101
+
102
+ Cartograph can also handle the event of root keys in response bodies. For example, if you receive a response with:
103
+
104
+ ```json
105
+ { "user": { "id": 123 } }
106
+ ```
107
+
108
+ You could define a mapping like this:
109
+
110
+
111
+ ```ruby
112
+ class UserMapping
113
+ include Cartograph::DSL
114
+
115
+ cartograph do
116
+ mapping User
117
+ root_key singular: 'user', plural: 'users', scopes: [:read]
118
+ property :id, scopes: [:read]
119
+ end
120
+ end
121
+ ```
122
+
123
+ This means that when you call the same thing:
124
+
125
+ ```ruby
126
+ response = HTTPClient.get("http://something.com/api/users")
127
+ users = UserMapping.extract_collection(response.body, :read)
128
+ ```
129
+
130
+ It will look for the root key before trying to deserialize the JSON response.
131
+ The advantage of this is it will only use the root key if there is a scope defined for it.
132
+
133
+
134
+ ### Including other definitions within eachother
135
+
136
+ Sometimes you might have models that are nested within eachother on responses. Or you simply want to cleanup definitions by separating concerns. Cartograph lets you do this with includes.
137
+
138
+ ```ruby
139
+ class UserMapping
140
+ include Cartograph::DSL
141
+
142
+ cartograph do
143
+ mapping User
144
+ property :id, scopes: [:read]
145
+ property :comments, plural: true, include: CommentMapping
146
+ end
147
+ end
148
+
149
+ class CommentMapping
150
+ include Cartograph::DSL
151
+
152
+ cartograph do
153
+ mapping Comment
154
+ property :id, scopes: [:read]
155
+ property :text, scopes: [:read]
156
+ end
157
+ end
158
+ ```
159
+
160
+
161
+ ### Scope blocks
162
+
163
+ Sometimes adding scopes to all properties can be tedious, to avoid that, you can define properties within a scope block.
164
+
165
+ ```ruby
166
+ class UserMapping
167
+ include Cartograph::DSL
168
+
169
+ cartograph do
170
+ scoped :read do
171
+ property :name
172
+ property :id
173
+ property :email, key: 'email_address' # The JSON returned has the key of email_address, our property is called email however.
174
+ end
175
+
176
+ scoped :update, :create do
177
+ property :name
178
+ property :email, key: 'email_address'
179
+ end
180
+ end
181
+ end
182
+ ```
183
+
184
+ Now when JSON includes comments for a user, it will know how to map the comments using the provided Cartograph definition.
185
+
186
+ ---
187
+
188
+ ### Caching
189
+
190
+ Cartograph has the option to cache certain serializations, determined by the way you setup the key.
191
+
192
+ ```ruby
193
+ class UserMapping
194
+ include Cartograph::DSL
195
+
196
+ cartograph do
197
+ cache { Rails.cache } # As long as this respond to #fetch(key_name, options = {}, &block) it will work
198
+ cache_key { |object| object.cache_key }
199
+
200
+ end
201
+ end
202
+ end
203
+ ```
204
+
205
+ ## Contributing
206
+
207
+ 1. Fork it ( https://github.com/kyrylo/cartograph/fork )
208
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
209
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
210
+ 4. Push to the branch (`git push origin my-new-feature`)
211
+ 5. Create a new Pull Request
@@ -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,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cartograph/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cartograph"
8
+ spec.version = Cartograph::VERSION
9
+ spec.authors = ["Robert Ross", "Kyrylo Silin"]
10
+ spec.email = ["silin@kyrylo.org"]
11
+ spec.summary = %q{Cartograph makes it easy to generate and convert JSON. It's intention is to be used for API clients.}
12
+ spec.description = %q{Cartograph makes it easy to generate and convert JSON. It's intention is to be used for API clients.}
13
+ spec.homepage = "https://github.com/kyrylo/cartograph"
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_development_dependency 'rake', '~> 12.0'
22
+ spec.add_development_dependency 'rspec', '~> 3.6'
23
+ spec.add_development_dependency 'pry', '~> 0'
24
+ end
@@ -0,0 +1,41 @@
1
+ require 'cartograph'
2
+ require 'pp'
3
+
4
+ class User < Struct.new(:id, :name, :comments)
5
+ end
6
+
7
+ class Comment < Struct.new(:id, :text)
8
+ end
9
+
10
+ class UserMapping
11
+ include Cartograph::DSL
12
+
13
+ cartograph do
14
+ mapping User
15
+
16
+ property :id, scopes: [:read]
17
+ property :name, scopes: [:read, :create]
18
+
19
+ property :comments, plural: true, scopes: [:read] do
20
+ mapping Comment
21
+
22
+ property :id, scopes: [:read]
23
+ property :text, scopes: [:read, :create]
24
+ end
25
+ end
26
+ end
27
+
28
+ user = User.new(1, 'he@he.com')
29
+ comment = Comment.new(12, 'aksjdfhasjkdfh')
30
+
31
+ user.comments = Array.new(3, comment)
32
+ users = Array.new(4, user)
33
+
34
+ json = UserMapping.represent_collection_for(:read, users)
35
+ puts "The JSON generated from that collection:"
36
+ puts json
37
+
38
+ users_again = UserMapping.extract_collection(json, :read)
39
+ puts "\n"
40
+ puts "And the JSON slurped back into an array:"
41
+ pp users_again
@@ -0,0 +1,54 @@
1
+ require 'cartograph'
2
+
3
+ json = '{
4
+ "domains": [
5
+ {
6
+ "name": "example.com",
7
+ "ttl": 1800,
8
+ "zone_file": "Example zone file text..."
9
+ }
10
+ ],
11
+ "meta": {
12
+ "total": 1
13
+ }
14
+ }'
15
+
16
+ class Domain
17
+ attr_accessor :name, :ttl, :zone_file
18
+ end
19
+
20
+ class MetaInformation
21
+ attr_accessor :total
22
+ end
23
+
24
+ class DomainMapper
25
+ include Cartograph::DSL
26
+
27
+ cartograph do
28
+ mapping Domain
29
+ root_key singular: 'domain', plural: 'domains', scopes: [:read]
30
+
31
+ property :name, scopes: [:read]
32
+ property :ttl, scopes: [:read]
33
+ property :zone_file, scopes: [:read]
34
+ end
35
+ end
36
+
37
+ class MetaInformationMapper
38
+ include Cartograph::DSL
39
+
40
+ cartograph do
41
+ mapping MetaInformation
42
+
43
+ root_key singular: 'meta', scopes: [:read]
44
+ property :total, scopes: [:read]
45
+ end
46
+ end
47
+
48
+ domains = DomainMapper.extract_collection(json, :read)
49
+ meta = MetaInformationMapper.extract_single(json, :read)
50
+
51
+ puts "Total Domains: #{domains.size}"
52
+ puts domains.map(&:name)
53
+ puts
54
+ puts "Total pages: #{meta.total}"
@@ -0,0 +1,24 @@
1
+ class Domain
2
+ attr_accessor :name, :ttl, :zone_file
3
+ end
4
+
5
+ class DomainMapper
6
+ include Cartograph::DSL
7
+
8
+ cartograph do
9
+ mapping Domain
10
+ root_key singular: 'domain', plural: 'domains', scopes: [:read]
11
+
12
+ property :name, scopes: [:read, :create]
13
+ property :ttl, scopes: [:read, :create]
14
+ property :zone_file, scopes: [:read]
15
+ end
16
+ end
17
+
18
+ domain = Domain.new
19
+ domain.name = 'example.com'
20
+ domain.ttl = 3600
21
+ domain.zone_file = "this wont be represented for create"
22
+
23
+ puts DomainMapper.representation_for(:create, domain)
24
+ #=> {"name":"example.com","ttl":3600}