kartograph 0.0.1 → 0.0.2
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.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/README.md +92 -1
- data/examples/domains.rb +54 -0
- data/examples/representation_for.rb +24 -0
- data/kartograph.gemspec +1 -0
- data/lib/kartograph.rb +9 -1
- data/lib/kartograph/artist.rb +22 -0
- data/lib/kartograph/dsl.rb +58 -0
- data/lib/kartograph/map.rb +32 -0
- data/lib/kartograph/property.rb +43 -0
- data/lib/kartograph/property_collection.rb +20 -0
- data/lib/kartograph/root_key.rb +19 -0
- data/lib/kartograph/sculptor.rb +26 -0
- data/lib/kartograph/version.rb +1 -1
- data/spec/lib/kartograph/artist_spec.rb +70 -0
- data/spec/lib/kartograph/dsl_spec.rb +125 -0
- data/spec/lib/kartograph/map_spec.rb +46 -0
- data/spec/lib/kartograph/property_collection_spec.rb +15 -0
- data/spec/lib/kartograph/property_spec.rb +155 -0
- data/spec/lib/kartograph/root_key_spec.rb +33 -0
- data/spec/lib/kartograph/sculptor_spec.rb +76 -0
- data/spec/spec_helper.rb +66 -0
- data/spec/support/dsl_contexts.rb +22 -0
- data/spec/support/dummy_comment.rb +2 -0
- data/spec/support/dummy_user.rb +2 -0
- metadata +49 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d0486e484ee7a91e233645567afcf28f2ff25d6b
|
|
4
|
+
data.tar.gz: 0b6232dbd15c7a27a90f89b00652abdc4912a789
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 389d7c025aad932d0f22e2d5b3fa1d03d907bd5af1cb06d916549af5caadfc10c47ee975ef3a0d5c4c9de6ea093bfc039bf2b9dccd8e34345ca5a9f5a6c0d994
|
|
7
|
+
data.tar.gz: aeff8daa983de66a69c76a7c73e995d91ce28b977c2749c7eba257ecda38294ba6d4653eb0f16c03f8bcac860003cd4b072dc44cecd1e25d1cb265d7a1f6092a
|
data/.rspec
ADDED
data/README.md
CHANGED
|
@@ -18,7 +18,98 @@ Or install it yourself as:
|
|
|
18
18
|
|
|
19
19
|
## Usage
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Kartograph makes it easy to generate and convert JSON. It's intention is to be used for API clients.
|
|
22
|
+
|
|
23
|
+
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:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
class UserMapping
|
|
27
|
+
include Kartograph::DSL
|
|
28
|
+
|
|
29
|
+
kartograph do
|
|
30
|
+
mapping User # The object we're mapping
|
|
31
|
+
|
|
32
|
+
property :name, scopes: [:create, :update]
|
|
33
|
+
property :id, scopes: [:read]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
user = User.new(name: 'Bobby Tables')
|
|
38
|
+
json_for_create = UserMapping.representation_for(:create, user)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
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:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
response = HTTPClient.post("http://something.com/api/users", body: json_for_create)
|
|
45
|
+
created_user = UserMapping.extract_single(response.body, :read)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Most API's will have a way of retrieving an entire resource collection. For this you can instruct Kartograph to convert a collection.
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
response = HTTPClient.get("http://something.com/api/users")
|
|
52
|
+
users = UserMapping.extract_collection(response.body, :read)
|
|
53
|
+
# => [ User, User, User ]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Getting Harder
|
|
57
|
+
|
|
58
|
+
Sometimes resources will nest other properties under a key. Kartograph can handle this as well.
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
class UserMapping
|
|
62
|
+
include Kartograph::DSL
|
|
63
|
+
|
|
64
|
+
kartograph do
|
|
65
|
+
mapping User # The object we're mapping
|
|
66
|
+
|
|
67
|
+
property :name, scopes: [:read]
|
|
68
|
+
|
|
69
|
+
property :comments do
|
|
70
|
+
mapping Comment # The nested object we're mapping
|
|
71
|
+
|
|
72
|
+
property :text, scopes: [:read]
|
|
73
|
+
property :author, scopes: [:read]
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Just like the previous examples, when you serialize this. It will include the comment block for the scope defined.
|
|
80
|
+
|
|
81
|
+
### Root Keys
|
|
82
|
+
|
|
83
|
+
Kartograph can also handle the event of root keys in response bodies. For example, if you receive a response with:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{ "user": { "id": 123 } }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
You could define a mapping like this:
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
class UserMapping
|
|
94
|
+
include Kartograph::DSL
|
|
95
|
+
|
|
96
|
+
kartograph do
|
|
97
|
+
mapping User
|
|
98
|
+
root_key singular: 'user', plural: 'users' scopes: [:read]
|
|
99
|
+
property :id, scopes: [:read]
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
This means that when you call the same thing:
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
response = HTTPClient.get("http://something.com/api/users")
|
|
108
|
+
users = UserMapping.extract_collection(response.body, :read)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
It will look for the root key before trying to deserialize the JSON response.
|
|
112
|
+
The advantage of this is it will only use the root key if there is a scope defined for it.
|
|
22
113
|
|
|
23
114
|
## Contributing
|
|
24
115
|
|
data/examples/domains.rb
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'kartograph'
|
|
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 Kartograph::DSL
|
|
26
|
+
|
|
27
|
+
kartograph 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 Kartograph::DSL
|
|
39
|
+
|
|
40
|
+
kartograph 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 Kartograph::DSL
|
|
7
|
+
|
|
8
|
+
kartograph 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}
|
data/kartograph.gemspec
CHANGED
data/lib/kartograph.rb
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
require "kartograph/version"
|
|
2
|
+
require 'json'
|
|
2
3
|
|
|
3
4
|
module Kartograph
|
|
4
|
-
|
|
5
|
+
autoload :DSL, 'kartograph/dsl'
|
|
6
|
+
autoload :Map, 'kartograph/map'
|
|
7
|
+
autoload :Property, 'kartograph/property'
|
|
8
|
+
autoload :PropertyCollection, 'kartograph/property_collection'
|
|
9
|
+
autoload :RootKey, 'kartograph/root_key'
|
|
10
|
+
|
|
11
|
+
autoload :Artist, 'kartograph/artist'
|
|
12
|
+
autoload :Sculptor, 'kartograph/sculptor'
|
|
5
13
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Kartograph
|
|
2
|
+
class Artist
|
|
3
|
+
attr_reader :object, :map
|
|
4
|
+
|
|
5
|
+
def initialize(object, map)
|
|
6
|
+
@object = object
|
|
7
|
+
@map = map
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def properties
|
|
11
|
+
map.properties
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def draw(scope = nil)
|
|
15
|
+
scoped_properties = scope ? properties.filter_by_scope(scope) : properties
|
|
16
|
+
scoped_properties.each_with_object({}) do |property, mapped|
|
|
17
|
+
raise ArgumentError, "#{object} does not respond to #{property.name}, so we can't map it" unless object.respond_to?(property.name)
|
|
18
|
+
mapped[property.name] = property.value_for(object, scope)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Kartograph
|
|
2
|
+
module DSL
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.extend ClassMethods
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module ClassMethods
|
|
8
|
+
def kartograph(&block)
|
|
9
|
+
@kartograph_map ||= Map.new
|
|
10
|
+
|
|
11
|
+
block.arity > 0 ? block.call(@kartograph_map) : @kartograph_map.instance_eval(&block)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def representation_for(scope, object, dumper = JSON)
|
|
15
|
+
drawed = Artist.new(object, @kartograph_map).draw(scope)
|
|
16
|
+
|
|
17
|
+
retrieve_root_key(scope, :singular) do |root_key|
|
|
18
|
+
# Reassign drawed if a root key exists
|
|
19
|
+
drawed = { root_key => drawed }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
dumper.dump(drawed)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def extract_single(content, scope, loader = JSON)
|
|
26
|
+
loaded = loader.load(content)
|
|
27
|
+
|
|
28
|
+
retrieve_root_key(scope, :singular) do |root_key|
|
|
29
|
+
# Reassign loaded if a root key exists
|
|
30
|
+
loaded = loaded[root_key]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Sculptor.new(loaded, @kartograph_map).sculpt(scope)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def extract_collection(content, scope, loader = JSON)
|
|
37
|
+
loaded = loader.load(content)
|
|
38
|
+
|
|
39
|
+
retrieve_root_key(scope, :plural) do |root_key|
|
|
40
|
+
# Reassign loaded if a root key exists
|
|
41
|
+
loaded = loaded[root_key]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
loaded.map do |object|
|
|
45
|
+
Sculptor.new(object, @kartograph_map).sculpt(scope)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def retrieve_root_key(scope, type, &block)
|
|
52
|
+
if root_key = @kartograph_map.root_key_for(scope, type)
|
|
53
|
+
yield root_key
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Kartograph
|
|
2
|
+
class Map
|
|
3
|
+
def property(*args, &block)
|
|
4
|
+
properties << Property.new(*args, &block)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def properties
|
|
8
|
+
@properties ||= PropertyCollection.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def root_keys
|
|
12
|
+
@root_keys ||= []
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def mapping(klass = nil)
|
|
16
|
+
@mapping = klass if klass
|
|
17
|
+
@mapping
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def root_key(options)
|
|
21
|
+
root_keys << RootKey.new(options)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def root_key_for(scope, type)
|
|
25
|
+
return unless %i(singular plural).include?(type)
|
|
26
|
+
|
|
27
|
+
if (root_key = root_keys.select {|rk| rk.scopes.include?(scope) }[0])
|
|
28
|
+
root_key.send(type)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Kartograph
|
|
2
|
+
class Property
|
|
3
|
+
attr_reader :name, :options, :map
|
|
4
|
+
|
|
5
|
+
def initialize(name, options = {}, &block)
|
|
6
|
+
@name = name
|
|
7
|
+
@options = options
|
|
8
|
+
|
|
9
|
+
if block_given?
|
|
10
|
+
@map ||= Map.new
|
|
11
|
+
block.arity > 0 ? block.call(map) : map.instance_eval(&block)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def value_for(object, scope = nil)
|
|
16
|
+
value = object.send(name)
|
|
17
|
+
map ? artist_value(value, scope) : value
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def value_from(object, scope = nil)
|
|
21
|
+
value = object.has_key?(name) ? object[name] : object[name.to_s]
|
|
22
|
+
map ? sculpt_value(value, scope) : value
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def scopes
|
|
26
|
+
options[:scopes] || []
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def plural?
|
|
30
|
+
!!options[:plural]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def sculpt_value(value, scope)
|
|
36
|
+
plural? ? value.map {|v| Sculptor.new(v, map).sculpt(scope) } : Sculptor.new(value, map).sculpt(scope)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def artist_value(value, scope)
|
|
40
|
+
plural? ? value.map {|v| Artist.new(v, map).draw(scope) } : Artist.new(value, map).draw(scope)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
|
|
3
|
+
module Kartograph
|
|
4
|
+
class PropertyCollection
|
|
5
|
+
# Make this collection quack like an array
|
|
6
|
+
# http://words.steveklabnik.com/beware-subclassing-ruby-core-classes
|
|
7
|
+
extend Forwardable
|
|
8
|
+
def_delegators :@collection, *(Array.instance_methods - Object.instance_methods)
|
|
9
|
+
|
|
10
|
+
def initialize(*)
|
|
11
|
+
@collection = []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def filter_by_scope(scope)
|
|
15
|
+
select do |property|
|
|
16
|
+
property.scopes.include?(scope)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Kartograph
|
|
2
|
+
class RootKey
|
|
3
|
+
attr_reader :options
|
|
4
|
+
|
|
5
|
+
def initialize(options = {})
|
|
6
|
+
@options = options
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def scopes
|
|
10
|
+
options[:scopes] || []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
%i(singular plural).each do |method|
|
|
14
|
+
define_method(method) do
|
|
15
|
+
options[method]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Kartograph
|
|
2
|
+
class Sculptor
|
|
3
|
+
attr_reader :object, :map
|
|
4
|
+
|
|
5
|
+
def initialize(object, map)
|
|
6
|
+
@object = object
|
|
7
|
+
@map = map
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def properties
|
|
11
|
+
map.properties
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def sculpt(scope = nil)
|
|
15
|
+
# Initializing the object we're coercing so we can set attributes on it
|
|
16
|
+
coerced = map.mapping.new
|
|
17
|
+
scoped_properties = scope ? properties.filter_by_scope(scope) : properties
|
|
18
|
+
|
|
19
|
+
scoped_properties.each_with_object(coerced) do |property, mutable|
|
|
20
|
+
setter_method = "#{property.name}="
|
|
21
|
+
value = property.value_from(object, scope)
|
|
22
|
+
mutable.send(setter_method, value)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/kartograph/version.rb
CHANGED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Kartograph::Artist do
|
|
4
|
+
let(:map) { Kartograph::Map.new }
|
|
5
|
+
let(:properties) { map.properties }
|
|
6
|
+
|
|
7
|
+
describe '#initialize' do
|
|
8
|
+
it 'initializes with an object and a map' do
|
|
9
|
+
object = double('object', name: 'hello')
|
|
10
|
+
properties << Kartograph::Property.new(:name)
|
|
11
|
+
|
|
12
|
+
artist = Kartograph::Artist.new(object, map)
|
|
13
|
+
|
|
14
|
+
expect(artist.object).to be(object)
|
|
15
|
+
expect(artist.map).to be(map)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe '#draw' do
|
|
20
|
+
it 'returns a hash of mapped properties' do
|
|
21
|
+
object = double('object', hello: 'world')
|
|
22
|
+
properties << Kartograph::Property.new(:hello)
|
|
23
|
+
|
|
24
|
+
artist = Kartograph::Artist.new(object, map)
|
|
25
|
+
masterpiece = artist.draw
|
|
26
|
+
|
|
27
|
+
expect(masterpiece).to include(hello: 'world')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'raises for a property that the object does not have' do
|
|
31
|
+
object = double('object')
|
|
32
|
+
properties << Kartograph::Property.new(:bunk)
|
|
33
|
+
artist = Kartograph::Artist.new(object, map)
|
|
34
|
+
|
|
35
|
+
expect { artist.draw }.to raise_error(ArgumentError).with_message("#{object} does not respond to bunk, so we can't map it")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context 'for filtered drawing' do
|
|
39
|
+
it 'only returns the scoped properties' do
|
|
40
|
+
object = double('object', hello: 'world', foo: 'bar')
|
|
41
|
+
properties << Kartograph::Property.new(:hello, scopes: [:create, :read])
|
|
42
|
+
properties << Kartograph::Property.new(:foo, scopes: [:create])
|
|
43
|
+
|
|
44
|
+
artist = Kartograph::Artist.new(object, map)
|
|
45
|
+
masterpiece = artist.draw(:read)
|
|
46
|
+
|
|
47
|
+
expect(masterpiece).to eq(hello: 'world')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context 'on nested properties' do
|
|
51
|
+
it 'only returns the nested properties within the same scope' do
|
|
52
|
+
child = double('child', hello: 'world', foo: 'bunk')
|
|
53
|
+
object = double('object', child: child)
|
|
54
|
+
|
|
55
|
+
root_property = Kartograph::Property.new(:child, scopes: [:create, :read]) do
|
|
56
|
+
property :hello, scopes: [:create]
|
|
57
|
+
property :foo, scopes: [:read]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
properties << root_property
|
|
61
|
+
|
|
62
|
+
artist = Kartograph::Artist.new(object, map)
|
|
63
|
+
masterpiece = artist.draw(:read)
|
|
64
|
+
|
|
65
|
+
expect(masterpiece).to eq(child: { foo: child.foo })
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Kartograph::DSL do
|
|
4
|
+
describe 'Inclusion' do
|
|
5
|
+
it 'gives you a class method for .kartograph' do
|
|
6
|
+
klass = Class.new
|
|
7
|
+
expect { klass.send(:include, described_class) }.to change { klass.respond_to?(:kartograph) }.to(true)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '.kartograph' do
|
|
12
|
+
subject(:mapping) { Class.new { include Kartograph::DSL } }
|
|
13
|
+
|
|
14
|
+
it 'yields a Kartograph::Map instance' do
|
|
15
|
+
expect {|b| mapping.kartograph(&b) }.to yield_with_args(instance_of(Kartograph::Map))
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe '.representation_for' do
|
|
20
|
+
include_context 'DSL Objects'
|
|
21
|
+
|
|
22
|
+
it 'returns the JSON representation for an object' do
|
|
23
|
+
json = mapped.representation_for(:create, object)
|
|
24
|
+
expect(json).to eq(
|
|
25
|
+
{ name: object.name }.to_json
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'with a root key for the scope' do
|
|
30
|
+
it 'returns the json with the root key' do
|
|
31
|
+
mapped.kartograph do
|
|
32
|
+
root_key singular: 'user', scopes: [:create]
|
|
33
|
+
end
|
|
34
|
+
json = mapped.representation_for(:create, object)
|
|
35
|
+
|
|
36
|
+
expect(json).to eq(
|
|
37
|
+
{
|
|
38
|
+
user: {
|
|
39
|
+
name: object.name
|
|
40
|
+
}
|
|
41
|
+
}.to_json
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe '.extract_single' do
|
|
48
|
+
include_context 'DSL Objects'
|
|
49
|
+
let(:json) do
|
|
50
|
+
{ id: 1337, name: 'Paul the octopus' }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'returns a populated object from a JSON representation' do
|
|
54
|
+
extracted = mapped.extract_single(json.to_json, :read)
|
|
55
|
+
|
|
56
|
+
expect(extracted.id).to eq(1337)
|
|
57
|
+
expect(extracted.name).to eq('Paul the octopus')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context 'with a root key in the JSON' do
|
|
61
|
+
let(:json) { { test: super() } }
|
|
62
|
+
|
|
63
|
+
before do
|
|
64
|
+
mapped.kartograph do
|
|
65
|
+
root_key singular: 'test', scopes: [:read]
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'traverses into the key and pulls the object from there' do
|
|
70
|
+
extracted = mapped.extract_single(json.to_json, :read)
|
|
71
|
+
|
|
72
|
+
expect(extracted.id).to eq(1337)
|
|
73
|
+
expect(extracted.name).to eq('Paul the octopus')
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe '.extract_collection' do
|
|
79
|
+
include_context 'DSL Objects'
|
|
80
|
+
let(:json) do
|
|
81
|
+
[
|
|
82
|
+
{ id: 1337, name: 'Paul the octopus' },
|
|
83
|
+
{ id: 1338, name: 'Hank the octopus' }
|
|
84
|
+
]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'returns a collection of objects from the json' do
|
|
88
|
+
extracted = mapped.extract_collection(json.to_json, :read)
|
|
89
|
+
|
|
90
|
+
expect(extracted.size).to be(2)
|
|
91
|
+
expect(extracted).to all(be_kind_of(DummyUser))
|
|
92
|
+
|
|
93
|
+
expect(extracted[0].id).to eq(json[0][:id])
|
|
94
|
+
expect(extracted[0].name).to eq(json[0][:name])
|
|
95
|
+
|
|
96
|
+
expect(extracted[1].id).to eq(json[1][:id])
|
|
97
|
+
expect(extracted[1].name).to eq(json[1][:name])
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
context 'for a nested key' do
|
|
101
|
+
let(:json) { { users: super() } }
|
|
102
|
+
|
|
103
|
+
before do
|
|
104
|
+
mapped.kartograph do
|
|
105
|
+
root_key plural: 'users', scopes: [:read]
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it 'returns a collection of objects from the json' do
|
|
110
|
+
extracted = mapped.extract_collection(json.to_json, :read)
|
|
111
|
+
|
|
112
|
+
expect(extracted.size).to be(2)
|
|
113
|
+
expect(extracted).to all(be_kind_of(DummyUser))
|
|
114
|
+
|
|
115
|
+
scoped = json[:users]
|
|
116
|
+
|
|
117
|
+
expect(extracted[0].id).to eq(scoped[0][:id])
|
|
118
|
+
expect(extracted[0].name).to eq(scoped[0][:name])
|
|
119
|
+
|
|
120
|
+
expect(extracted[1].id).to eq(scoped[1][:id])
|
|
121
|
+
expect(extracted[1].name).to eq(scoped[1][:name])
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Kartograph::Map do
|
|
4
|
+
subject(:map) { Kartograph::Map.new }
|
|
5
|
+
|
|
6
|
+
describe '#property' do
|
|
7
|
+
it 'adds a property to the map' do
|
|
8
|
+
map.property :attribute_name, scopes: [:read]
|
|
9
|
+
expect(map.properties.size).to be(1)
|
|
10
|
+
expect(map.properties.first).to be_kind_of(Kartograph::Property)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe '#properties' do
|
|
15
|
+
it 'returns a PropertyCollection object' do
|
|
16
|
+
properties = map.properties
|
|
17
|
+
expect(properties).to be_kind_of(Kartograph::PropertyCollection)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe '#mapping' do
|
|
22
|
+
it 'sets the class we\'re mapping' do
|
|
23
|
+
map.mapping Class
|
|
24
|
+
expect(map.mapping).to be(Class)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe '#root_key' do
|
|
29
|
+
it 'sets the root keys' do
|
|
30
|
+
map.root_key singlular: 'test', scopes: [:read]
|
|
31
|
+
map.root_key singlular: 'test', scopes: [:create]
|
|
32
|
+
|
|
33
|
+
expect(map.root_keys.size).to be(2)
|
|
34
|
+
expect(map.root_keys).to all(be_kind_of(Kartograph::RootKey))
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe '#root_key_for' do
|
|
39
|
+
it 'returns the first root key for the scope and type' do
|
|
40
|
+
map.root_key singular: 'test', scopes: [:read]
|
|
41
|
+
key = map.root_key_for(:read, :singular)
|
|
42
|
+
|
|
43
|
+
expect(key).to eq('test')
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Kartograph::PropertyCollection do
|
|
4
|
+
describe '#filter_by_scope' do
|
|
5
|
+
it 'only returns properties with a certain scope attached' do
|
|
6
|
+
collection = Kartograph::PropertyCollection.new
|
|
7
|
+
collection << Kartograph::Property.new(:hello, scopes: [:read, :create])
|
|
8
|
+
collection << Kartograph::Property.new(:id, scopes: [:read])
|
|
9
|
+
|
|
10
|
+
filtered = collection.filter_by_scope(:create)
|
|
11
|
+
expect(filtered.size).to be(1)
|
|
12
|
+
expect(filtered.first.name).to eq(:hello)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Kartograph::Property do
|
|
4
|
+
describe '#initialize' do
|
|
5
|
+
it 'initializes with an attribute name and options' do
|
|
6
|
+
name = :hey
|
|
7
|
+
options = { lol: 'whut' }
|
|
8
|
+
|
|
9
|
+
property = Kartograph::Property.new(name, options)
|
|
10
|
+
expect(property.name).to eq(name)
|
|
11
|
+
expect(property.options).to eq(options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
context 'with a block' do
|
|
15
|
+
it 'yields a map instance for the property' do
|
|
16
|
+
expect {|b| Kartograph::Property.new(:hello, &b) }.to yield_with_args(instance_of(Kartograph::Map))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe '#scopes' do
|
|
22
|
+
it 'returns the scopes that the property is for' do
|
|
23
|
+
property = Kartograph::Property.new(:name, scopes: [:read, :create])
|
|
24
|
+
expect(property.scopes).to include(:read, :create)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'returns an empty array when no scopes are provided' do
|
|
28
|
+
property = Kartograph::Property.new(:name)
|
|
29
|
+
expect(property.scopes).to eq( [] )
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe '#plural?' do
|
|
34
|
+
it 'returns true when set to plural' do
|
|
35
|
+
property = Kartograph::Property.new(:name, scopes: [:read], plural: true)
|
|
36
|
+
expect(property).to be_plural
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'returns false when not set' do
|
|
40
|
+
property = Kartograph::Property.new(:name, scopes: [:read])
|
|
41
|
+
expect(property).to_not be_plural
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe '#value_for' do
|
|
46
|
+
it 'returns the value when passed an object' do
|
|
47
|
+
property = Kartograph::Property.new(:sammy)
|
|
48
|
+
object = double('object', sammy: 'cephalopod')
|
|
49
|
+
|
|
50
|
+
expect(property.value_for(object)).to eq('cephalopod')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
context 'for a nested property set' do
|
|
54
|
+
it 'returns nested properties' do
|
|
55
|
+
top_level = Kartograph::Property.new(:sammy) do
|
|
56
|
+
property :cephalopod
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
child = double('child', cephalopod: 'I will ink you')
|
|
60
|
+
root = double('root', sammy: child)
|
|
61
|
+
|
|
62
|
+
expect(top_level.value_for(root)).to eq(cephalopod: child.cephalopod)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context 'when it is plural' do
|
|
66
|
+
it 'returns a pluralized representation' do
|
|
67
|
+
top_level = Kartograph::Property.new(:sammy, plural: true) do
|
|
68
|
+
property :cephalopod
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
child1 = double('child', cephalopod: 'I will ink you')
|
|
72
|
+
child2 = double('child', cephalopod: 'I wont because im cool')
|
|
73
|
+
|
|
74
|
+
root = double('root', sammy: [child1, child2])
|
|
75
|
+
|
|
76
|
+
expect(top_level.value_for(root)).to eq([
|
|
77
|
+
{ cephalopod: child1.cephalopod },
|
|
78
|
+
{ cephalopod: child2.cephalopod }
|
|
79
|
+
])
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe '#value_from' do
|
|
86
|
+
let(:hash) { { hello: 'world' } }
|
|
87
|
+
|
|
88
|
+
it 'retrieves the value from a hash for the property' do
|
|
89
|
+
property = Kartograph::Property.new(:hello)
|
|
90
|
+
expect(property.value_from(hash)).to eq('world')
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context 'string and symbol agnostic' do
|
|
94
|
+
let(:hash) { { 'hello' => 'world' } }
|
|
95
|
+
|
|
96
|
+
it 'retrieves the value from a hash for the property' do
|
|
97
|
+
property = Kartograph::Property.new(:hello)
|
|
98
|
+
expect(property.value_from(hash)).to eq('world')
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
context 'for a nested property set' do
|
|
103
|
+
it 'returns an object with the properties set on it' do
|
|
104
|
+
dummy_class = Struct.new(:id, :name)
|
|
105
|
+
|
|
106
|
+
nested_property = Kartograph::Property.new(:hello) do
|
|
107
|
+
mapping dummy_class
|
|
108
|
+
property :id
|
|
109
|
+
property :name
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
hash = { hello: {
|
|
113
|
+
'id' => 555,
|
|
114
|
+
'name' => 'Buckstar'
|
|
115
|
+
}}
|
|
116
|
+
|
|
117
|
+
value = nested_property.value_from(hash)
|
|
118
|
+
expect(value).to be_kind_of(dummy_class)
|
|
119
|
+
expect(value.id).to eq(hash[:hello]['id'])
|
|
120
|
+
expect(value.name).to eq(hash[:hello]['name'])
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'returns a collection of objects when set to plural' do
|
|
124
|
+
dummy_class = Struct.new(:id, :name)
|
|
125
|
+
|
|
126
|
+
nested_property = Kartograph::Property.new(:hello, plural: true) do
|
|
127
|
+
mapping dummy_class
|
|
128
|
+
|
|
129
|
+
property :id
|
|
130
|
+
property :name
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
hash = {
|
|
134
|
+
hello: [{
|
|
135
|
+
'id' => 555,
|
|
136
|
+
'name' => 'Buckstar'
|
|
137
|
+
}, {
|
|
138
|
+
'id' => 556,
|
|
139
|
+
'name' => 'Starbuck'
|
|
140
|
+
}]
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
value = nested_property.value_from(hash)
|
|
144
|
+
expect(value).to be_kind_of(Array)
|
|
145
|
+
expect(value.size).to be(2)
|
|
146
|
+
|
|
147
|
+
expect(value[0].id).to eq(hash[:hello][0]['id'])
|
|
148
|
+
expect(value[0].name).to eq(hash[:hello][0]['name'])
|
|
149
|
+
|
|
150
|
+
expect(value[1].id).to eq(hash[:hello][1]['id'])
|
|
151
|
+
expect(value[1].name).to eq(hash[:hello][1]['name'])
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Kartograph::RootKey do
|
|
4
|
+
describe '#initialize' do
|
|
5
|
+
it 'initializes with options' do
|
|
6
|
+
options = { singular: 'hello', plural: 'hellos', scopes: [:read] }
|
|
7
|
+
|
|
8
|
+
instance = Kartograph::RootKey.new(options)
|
|
9
|
+
expect(instance.options).to eq(options)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#scopes' do
|
|
14
|
+
it 'reads the scopes' do
|
|
15
|
+
instance = Kartograph::RootKey.new(scopes: [:read])
|
|
16
|
+
expect(instance.scopes).to eq([:read])
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '#singular' do
|
|
21
|
+
it 'reads the singular key' do
|
|
22
|
+
instance = Kartograph::RootKey.new(singular: 'user')
|
|
23
|
+
expect(instance.singular).to eq('user')
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe '#plural' do
|
|
28
|
+
it 'reads the plural key' do
|
|
29
|
+
instance = Kartograph::RootKey.new(plural: 'user')
|
|
30
|
+
expect(instance.plural).to eq('user')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Kartograph::Sculptor do
|
|
4
|
+
describe '#initialize' do
|
|
5
|
+
it 'initializes with a hash and map' do
|
|
6
|
+
hash = {}
|
|
7
|
+
map = double('im a map')
|
|
8
|
+
|
|
9
|
+
sculptor = Kartograph::Sculptor.new(hash, map)
|
|
10
|
+
|
|
11
|
+
expect(sculptor.object).to be(hash)
|
|
12
|
+
expect(sculptor.map).to be(map)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe '#sculpt' do
|
|
17
|
+
let(:map) { Kartograph::Map.new }
|
|
18
|
+
let(:object) { { 'id' => 343, 'name' => 'Guilty Spark' } }
|
|
19
|
+
|
|
20
|
+
context 'without a scope' do
|
|
21
|
+
before do
|
|
22
|
+
map.mapping DummyUser
|
|
23
|
+
map.property :id, scopes: [:read]
|
|
24
|
+
map.property :name, scopes: [:read, :create]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'returns a coerced user' do
|
|
28
|
+
sculptor = Kartograph::Sculptor.new(object, map)
|
|
29
|
+
sculpted = sculptor.sculpt
|
|
30
|
+
|
|
31
|
+
expect(sculpted).to be_kind_of(DummyUser)
|
|
32
|
+
expect(sculpted.id).to eq(object['id'])
|
|
33
|
+
expect(sculpted.name).to eq(object['name'])
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context 'with a scope' do
|
|
38
|
+
before do
|
|
39
|
+
map.mapping DummyUser
|
|
40
|
+
map.property :id, scopes: [:read]
|
|
41
|
+
map.property :name, scopes: [:create]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'returns a coerced user' do
|
|
45
|
+
sculptor = Kartograph::Sculptor.new(object, map)
|
|
46
|
+
sculpted = sculptor.sculpt(:read)
|
|
47
|
+
|
|
48
|
+
expect(sculpted).to be_kind_of(DummyUser)
|
|
49
|
+
expect(sculpted.id).to eq(object['id'])
|
|
50
|
+
expect(sculpted.name).to be_nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
context 'for nested properties' do
|
|
54
|
+
let(:object) { super().merge('comment' => { 'id' => 123, 'text' => 'hello' }) }
|
|
55
|
+
|
|
56
|
+
before do
|
|
57
|
+
map.property :comment, scopes: [:read] do
|
|
58
|
+
mapping DummyComment
|
|
59
|
+
|
|
60
|
+
property :id, scopes: [:read]
|
|
61
|
+
property :text, scopes: [:create]
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'returns the nested objects with scoped properties set' do
|
|
66
|
+
sculptor = Kartograph::Sculptor.new(object, map)
|
|
67
|
+
sculpted = sculptor.sculpt(:read)
|
|
68
|
+
|
|
69
|
+
expect(sculpted.comment).to be_kind_of(DummyComment)
|
|
70
|
+
expect(sculpted.comment.id).to eq(123)
|
|
71
|
+
expect(sculpted.comment.text).to be_nil
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'kartograph'
|
|
2
|
+
|
|
3
|
+
Dir['./spec/support/**/*.rb'].each {|f| load f }
|
|
4
|
+
|
|
5
|
+
RSpec.configure do |config|
|
|
6
|
+
# The settings below are suggested to provide a good initial experience
|
|
7
|
+
# with RSpec, but feel free to customize to your heart's content.
|
|
8
|
+
=begin
|
|
9
|
+
# These two settings work together to allow you to limit a spec run
|
|
10
|
+
# to individual examples or groups you care about by tagging them with
|
|
11
|
+
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
|
12
|
+
# get run.
|
|
13
|
+
config.filter_run :focus
|
|
14
|
+
config.run_all_when_everything_filtered = true
|
|
15
|
+
|
|
16
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
|
17
|
+
# file, and it's useful to allow more verbose output when running an
|
|
18
|
+
# individual spec file.
|
|
19
|
+
if config.files_to_run.one?
|
|
20
|
+
# Use the documentation formatter for detailed output,
|
|
21
|
+
# unless a formatter has already been configured
|
|
22
|
+
# (e.g. via a command-line flag).
|
|
23
|
+
config.default_formatter = 'doc'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Print the 10 slowest examples and example groups at the
|
|
27
|
+
# end of the spec run, to help surface which specs are running
|
|
28
|
+
# particularly slow.
|
|
29
|
+
config.profile_examples = 10
|
|
30
|
+
|
|
31
|
+
# Run specs in random order to surface order dependencies. If you find an
|
|
32
|
+
# order dependency and want to debug it, you can fix the order by providing
|
|
33
|
+
# the seed, which is printed after each run.
|
|
34
|
+
# --seed 1234
|
|
35
|
+
config.order = :random
|
|
36
|
+
|
|
37
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
|
38
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
|
39
|
+
# test failures related to randomization by passing the same `--seed` value
|
|
40
|
+
# as the one that triggered the failure.
|
|
41
|
+
Kernel.srand config.seed
|
|
42
|
+
|
|
43
|
+
# rspec-expectations config goes here. You can use an alternate
|
|
44
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
|
45
|
+
# assertions if you prefer.
|
|
46
|
+
config.expect_with :rspec do |expectations|
|
|
47
|
+
# Enable only the newer, non-monkey-patching expect syntax.
|
|
48
|
+
# For more details, see:
|
|
49
|
+
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
|
50
|
+
expectations.syntax = :expect
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
|
54
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
|
55
|
+
config.mock_with :rspec do |mocks|
|
|
56
|
+
# Enable only the newer, non-monkey-patching expect syntax.
|
|
57
|
+
# For more details, see:
|
|
58
|
+
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
|
59
|
+
mocks.syntax = :expect
|
|
60
|
+
|
|
61
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
|
62
|
+
# a real object. This is generally recommended.
|
|
63
|
+
mocks.verify_partial_doubles = true
|
|
64
|
+
end
|
|
65
|
+
=end
|
|
66
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
shared_context "DSL Objects" do
|
|
2
|
+
let(:object) { double('object', id: 1066, name: 'Bruce (the dude from Finding Nemo)') }
|
|
3
|
+
let(:mapped) do
|
|
4
|
+
Class.new do
|
|
5
|
+
include Kartograph::DSL
|
|
6
|
+
|
|
7
|
+
kartograph do
|
|
8
|
+
mapping DummyUser
|
|
9
|
+
|
|
10
|
+
property :id, scopes: [:read]
|
|
11
|
+
property :name, scopes: [:read, :create]
|
|
12
|
+
|
|
13
|
+
property :comments, plural: true do
|
|
14
|
+
mapping DummyComment
|
|
15
|
+
|
|
16
|
+
property :id, scopes: [:read]
|
|
17
|
+
property :text, scopes: [:read, :create]
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kartograph
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Ross
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-07-
|
|
11
|
+
date: 2014-07-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -52,6 +52,20 @@ dependencies:
|
|
|
52
52
|
- - ~>
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: 3.0.0
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: pry
|
|
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'
|
|
55
69
|
description: Short Description
|
|
56
70
|
email:
|
|
57
71
|
- rross@digitalocean.com
|
|
@@ -60,13 +74,34 @@ extensions: []
|
|
|
60
74
|
extra_rdoc_files: []
|
|
61
75
|
files:
|
|
62
76
|
- .gitignore
|
|
77
|
+
- .rspec
|
|
63
78
|
- Gemfile
|
|
64
79
|
- LICENSE.txt
|
|
65
80
|
- README.md
|
|
66
81
|
- Rakefile
|
|
82
|
+
- examples/domains.rb
|
|
83
|
+
- examples/representation_for.rb
|
|
67
84
|
- kartograph.gemspec
|
|
68
85
|
- lib/kartograph.rb
|
|
86
|
+
- lib/kartograph/artist.rb
|
|
87
|
+
- lib/kartograph/dsl.rb
|
|
88
|
+
- lib/kartograph/map.rb
|
|
89
|
+
- lib/kartograph/property.rb
|
|
90
|
+
- lib/kartograph/property_collection.rb
|
|
91
|
+
- lib/kartograph/root_key.rb
|
|
92
|
+
- lib/kartograph/sculptor.rb
|
|
69
93
|
- lib/kartograph/version.rb
|
|
94
|
+
- spec/lib/kartograph/artist_spec.rb
|
|
95
|
+
- spec/lib/kartograph/dsl_spec.rb
|
|
96
|
+
- spec/lib/kartograph/map_spec.rb
|
|
97
|
+
- spec/lib/kartograph/property_collection_spec.rb
|
|
98
|
+
- spec/lib/kartograph/property_spec.rb
|
|
99
|
+
- spec/lib/kartograph/root_key_spec.rb
|
|
100
|
+
- spec/lib/kartograph/sculptor_spec.rb
|
|
101
|
+
- spec/spec_helper.rb
|
|
102
|
+
- spec/support/dsl_contexts.rb
|
|
103
|
+
- spec/support/dummy_comment.rb
|
|
104
|
+
- spec/support/dummy_user.rb
|
|
70
105
|
homepage: ''
|
|
71
106
|
licenses:
|
|
72
107
|
- MIT
|
|
@@ -91,4 +126,15 @@ rubygems_version: 2.2.2
|
|
|
91
126
|
signing_key:
|
|
92
127
|
specification_version: 4
|
|
93
128
|
summary: Short Summary
|
|
94
|
-
test_files:
|
|
129
|
+
test_files:
|
|
130
|
+
- spec/lib/kartograph/artist_spec.rb
|
|
131
|
+
- spec/lib/kartograph/dsl_spec.rb
|
|
132
|
+
- spec/lib/kartograph/map_spec.rb
|
|
133
|
+
- spec/lib/kartograph/property_collection_spec.rb
|
|
134
|
+
- spec/lib/kartograph/property_spec.rb
|
|
135
|
+
- spec/lib/kartograph/root_key_spec.rb
|
|
136
|
+
- spec/lib/kartograph/sculptor_spec.rb
|
|
137
|
+
- spec/spec_helper.rb
|
|
138
|
+
- spec/support/dsl_contexts.rb
|
|
139
|
+
- spec/support/dummy_comment.rb
|
|
140
|
+
- spec/support/dummy_user.rb
|