yaks 0.3.1 → 0.4.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +0 -2
- data/LICENSE +7 -0
- data/README.md +160 -35
- data/Rakefile +2 -1
- data/lib/yaks/collection_mapper.rb +25 -18
- data/lib/yaks/collection_resource.rb +11 -17
- data/lib/yaks/config.rb +96 -0
- data/lib/yaks/default_policy.rb +34 -4
- data/lib/yaks/fp.rb +18 -0
- data/lib/yaks/mapper/association.rb +19 -27
- data/lib/yaks/mapper/class_methods.rb +4 -2
- data/lib/yaks/mapper/config.rb +24 -39
- data/lib/yaks/mapper/has_many.rb +7 -6
- data/lib/yaks/mapper/has_one.rb +4 -3
- data/lib/yaks/mapper/link.rb +52 -55
- data/lib/yaks/mapper.rb +38 -26
- data/lib/yaks/null_resource.rb +3 -3
- data/lib/yaks/primitivize.rb +29 -27
- data/lib/yaks/resource/link.rb +4 -0
- data/lib/yaks/resource.rb +18 -7
- data/lib/yaks/serializer/collection_json.rb +38 -0
- data/lib/yaks/serializer/hal.rb +55 -0
- data/lib/yaks/serializer/json_api.rb +61 -0
- data/lib/yaks/serializer.rb +25 -4
- data/lib/yaks/util.rb +2 -42
- data/lib/yaks/version.rb +1 -1
- data/lib/yaks.rb +10 -32
- data/notes.org +72 -0
- data/shaved_yak.gif +0 -0
- data/spec/acceptance/acceptance_spec.rb +46 -0
- data/spec/acceptance/models.rb +28 -0
- data/spec/integration/map_to_resource_spec.rb +11 -15
- data/spec/json/confucius.hal.json +23 -0
- data/spec/json/confucius.json_api.json +22 -0
- data/spec/json/john.hal.json +29 -0
- data/spec/json/youtypeitwepostit.collection.json +45 -0
- data/spec/spec_helper.rb +12 -1
- data/spec/support/shared_contexts.rb +7 -10
- data/spec/support/youtypeit_models_mappers.rb +20 -0
- data/spec/unit/yaks/collection_mapper_spec.rb +84 -0
- data/spec/unit/yaks/collection_resource_spec.rb +72 -0
- data/spec/unit/yaks/config_spec.rb +129 -0
- data/spec/unit/yaks/fp_spec.rb +31 -0
- data/spec/unit/yaks/mapper/association_spec.rb +80 -0
- data/spec/{yaks → unit/yaks}/mapper/class_methods_spec.rb +4 -4
- data/spec/unit/yaks/mapper/config_spec.rb +191 -0
- data/spec/unit/yaks/mapper/has_many_spec.rb +46 -0
- data/spec/unit/yaks/mapper/has_one_spec.rb +34 -0
- data/spec/unit/yaks/mapper/link_spec.rb +152 -0
- data/spec/unit/yaks/mapper_spec.rb +177 -0
- data/spec/unit/yaks/resource_spec.rb +40 -0
- data/spec/{yaks/hal_serializer_spec.rb → unit/yaks/serializer/hal_spec.rb} +2 -2
- data/spec/unit/yaks/serializer_spec.rb +12 -0
- data/spec/unit/yaks/util_spec.rb +43 -0
- data/spec/yaml/confucius.yaml +10 -0
- data/spec/yaml/youtypeitwepostit.yaml +9 -0
- data/yaks.gemspec +7 -8
- metadata +92 -53
- data/Gemfile.lock +0 -111
- data/lib/yaks/hal_serializer.rb +0 -59
- data/lib/yaks/json_api_serializer.rb +0 -59
- data/lib/yaks/link_lookup.rb +0 -23
- data/lib/yaks/mapper/lookup.rb +0 -19
- data/lib/yaks/mapper/map_links.rb +0 -17
- data/lib/yaks/profile_registry.rb +0 -60
- data/lib/yaks/rel_registry.rb +0 -20
- data/lib/yaks/shared_options.rb +0 -15
- data/spec/support/shorthands.rb +0 -22
- data/spec/yaks/collection_resource_spec.rb +0 -9
- data/spec/yaks/mapper/association_spec.rb +0 -21
- data/spec/yaks/mapper/config_spec.rb +0 -77
- data/spec/yaks/mapper/has_one_spec.rb +0 -16
- data/spec/yaks/mapper/link_spec.rb +0 -38
- data/spec/yaks/mapper/map_links_spec.rb +0 -46
- data/spec/yaks/mapper_spec.rb +0 -65
- data/spec/yaks/resource_spec.rb +0 -23
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Yaks
|
4
|
+
class Serializer
|
5
|
+
class Hal < self
|
6
|
+
Serializer.register self, :hal, 'application/hal+json'
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
def serialize_resource(resource)
|
11
|
+
# The HAL spec doesn't say explicitly how to deal missing values,
|
12
|
+
# looking at client behavior (Hyperagent) it seems safer to return an empty
|
13
|
+
# resource.
|
14
|
+
#
|
15
|
+
# return nil if resource.is_a? NullResource
|
16
|
+
result = resource.attributes
|
17
|
+
result = result.merge(:_links => serialize_links(resource.links)) unless resource.links.empty?
|
18
|
+
result = result.merge(:_embedded => serialize_embedded(resource.subresources)) unless resource.subresources.empty?
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
def serialize_links(links)
|
23
|
+
links.reduce({}, &method(:serialize_link))
|
24
|
+
end
|
25
|
+
|
26
|
+
def serialize_link(memo, link)
|
27
|
+
hal_link = {href: link.uri}
|
28
|
+
hal_link.merge!(link.options.reject{|k,_| k==:templated})
|
29
|
+
hal_link.merge!(templated: true) if link.templated?
|
30
|
+
|
31
|
+
memo[link.rel] = if singular?(link.rel)
|
32
|
+
hal_link
|
33
|
+
else
|
34
|
+
Array(memo[link.rel]) + [hal_link]
|
35
|
+
end
|
36
|
+
memo
|
37
|
+
end
|
38
|
+
|
39
|
+
def singular?(rel)
|
40
|
+
!options.fetch(:plural_links) { [] }.include?(rel)
|
41
|
+
end
|
42
|
+
|
43
|
+
def serialize_embedded(subresources)
|
44
|
+
subresources.each_with_object({}) do |(rel, resources), memo|
|
45
|
+
memo[rel] = if resources.collection?
|
46
|
+
resources.map( &method(:serialize_resource) )
|
47
|
+
else
|
48
|
+
serialize_resource(resources)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Yaks
|
4
|
+
class Serializer
|
5
|
+
class JsonApi < self
|
6
|
+
Serializer.register self, :json_api, 'application/vnd.api+json'
|
7
|
+
|
8
|
+
include FP
|
9
|
+
|
10
|
+
def call
|
11
|
+
serialized = {
|
12
|
+
pluralize(resource.type) => resource.map(&method(:serialize_resource))
|
13
|
+
}
|
14
|
+
|
15
|
+
linked = resource.each_with_object({}) do |res, hsh|
|
16
|
+
serialize_linked_subresources(res.subresources, hsh)
|
17
|
+
end
|
18
|
+
serialized = serialized.merge('linked' => linked)
|
19
|
+
|
20
|
+
serialized
|
21
|
+
end
|
22
|
+
alias serialize call
|
23
|
+
|
24
|
+
def serialize_resource(resource)
|
25
|
+
result = resource.attributes
|
26
|
+
result = result.merge(:links => serialize_links(resource.subresources)) unless resource.subresources.empty?
|
27
|
+
result
|
28
|
+
end
|
29
|
+
|
30
|
+
def serialize_links(subresources)
|
31
|
+
subresources.each_with_object({}) do |(name, resource), hsh|
|
32
|
+
hsh[pluralize(resource.type)] = serialize_link(resource)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def serialize_link(resource)
|
37
|
+
resource.collection? ? resource.map(&send_with_args(:[], :id)) : resource[:id]
|
38
|
+
end
|
39
|
+
|
40
|
+
def serialize_linked_subresources(subresources, hsh)
|
41
|
+
subresources.each_with_object(hsh) do |(name, resources), hsh|
|
42
|
+
serialize_linked_resources(resources, hsh)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def serialize_linked_resources(resources, linked)
|
47
|
+
resources.each_with_object(linked) do |resource, memo|
|
48
|
+
serialize_subresource(resource, memo)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# {shows => [{id: 3, name: 'foo'}]}
|
53
|
+
def serialize_subresource(resource, linked)
|
54
|
+
key = pluralize(resource.type)
|
55
|
+
set = linked.fetch(key) { Set.new }
|
56
|
+
linked = linked[key] = (set << serialize_resource(resource))
|
57
|
+
serialize_linked_subresources(resource.subresources, linked)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/yaks/serializer.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Yaks
|
2
2
|
class Serializer
|
3
3
|
extend Forwardable
|
4
|
-
include Util
|
4
|
+
include Util
|
5
5
|
|
6
6
|
attr_reader :resource, :options
|
7
7
|
def_delegators :resource, :links, :attributes, :subresources
|
@@ -13,10 +13,31 @@ module Yaks
|
|
13
13
|
@options = YAKS_DEFAULT_OPTIONS.merge(options)
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
(
|
18
|
-
profile_registry.find_by_uri(profile)
|
16
|
+
def call
|
17
|
+
serialize_resource(resource)
|
19
18
|
end
|
19
|
+
alias serialize call
|
20
20
|
|
21
|
+
class << self
|
22
|
+
def register(klass, name, mime_type)
|
23
|
+
@serializers ||= {}
|
24
|
+
@serializers[name] = klass
|
25
|
+
|
26
|
+
@mime_types ||= {}
|
27
|
+
@mime_types[mime_type] = klass
|
28
|
+
end
|
29
|
+
|
30
|
+
def by_name(name)
|
31
|
+
@serializers.fetch(name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def by_mime_type(mime_type)
|
35
|
+
@mime_types.fetch(mime_type)
|
36
|
+
end
|
37
|
+
|
38
|
+
def mime_types
|
39
|
+
@mime_types.keys
|
40
|
+
end
|
41
|
+
end
|
21
42
|
end
|
22
43
|
end
|
data/lib/yaks/util.rb
CHANGED
@@ -18,18 +18,6 @@ module Yaks
|
|
18
18
|
.gsub!(/(?:^|_)(.)/) { $1.upcase }
|
19
19
|
end
|
20
20
|
|
21
|
-
def List(*args)
|
22
|
-
Hamster.list(*args)
|
23
|
-
end
|
24
|
-
|
25
|
-
def Hash(*args)
|
26
|
-
Hamster.hash(*args)
|
27
|
-
end
|
28
|
-
|
29
|
-
def Set(*args)
|
30
|
-
Hamster.set(*args)
|
31
|
-
end
|
32
|
-
|
33
21
|
# Turn what is maybe a Proc into its result (or itself)
|
34
22
|
#
|
35
23
|
# When input can be either a value or a proc that returns a value,
|
@@ -44,9 +32,9 @@ module Yaks
|
|
44
32
|
# @param [Object] context
|
45
33
|
# (optional) A context used to instance_eval the proc
|
46
34
|
def Resolve(maybe_proc, context = nil)
|
47
|
-
if maybe_proc.
|
35
|
+
if maybe_proc.is_a? Proc or maybe_proc.is_a? Method
|
48
36
|
if context
|
49
|
-
if maybe_proc.
|
37
|
+
if maybe_proc.arity > 0
|
50
38
|
context.instance_eval(&maybe_proc)
|
51
39
|
else
|
52
40
|
# In case it's a lambda with zero arity instance_eval fails
|
@@ -60,33 +48,5 @@ module Yaks
|
|
60
48
|
end
|
61
49
|
end
|
62
50
|
|
63
|
-
def curry_method(name)
|
64
|
-
method(name).to_proc.curry
|
65
|
-
end
|
66
|
-
alias μ curry_method
|
67
|
-
|
68
|
-
def identity_function
|
69
|
-
->(x) {x}
|
70
|
-
end
|
71
|
-
alias ι identity_function
|
72
|
-
|
73
|
-
def juxt(*procs)
|
74
|
-
->(*args) { procs.map &σ(:call, *args) }
|
75
|
-
end
|
76
|
-
|
77
|
-
def curry_symbol(symbol, *args, &blk)
|
78
|
-
->(obj) { obj.method(symbol).to_proc.curry.(*args, &blk) }
|
79
|
-
end
|
80
|
-
alias σ curry_symbol
|
81
|
-
alias send_with_args curry_symbol
|
82
|
-
|
83
|
-
def extract_options(args)
|
84
|
-
if args.last.is_a? Hash
|
85
|
-
[args.take(args.count-1), args.last]
|
86
|
-
else
|
87
|
-
[args, {}]
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
51
|
end
|
92
52
|
end
|
data/lib/yaks/version.rb
CHANGED
data/lib/yaks.rb
CHANGED
@@ -1,54 +1,31 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
3
|
require 'forwardable'
|
4
|
+
require 'set'
|
4
5
|
|
5
|
-
require 'hamster'
|
6
6
|
require 'concord'
|
7
7
|
require 'inflection'
|
8
8
|
require 'uri_template'
|
9
|
+
require 'rack/accept'
|
9
10
|
|
10
11
|
require 'yaks/util'
|
11
|
-
require 'yaks/
|
12
|
-
require 'yaks/shared_options'
|
12
|
+
require 'yaks/fp'
|
13
13
|
require 'yaks/primitivize'
|
14
14
|
|
15
|
-
require 'yaks/profile_registry'
|
16
|
-
require 'yaks/rel_registry'
|
17
15
|
require 'yaks/default_policy'
|
18
16
|
|
19
17
|
module Yaks
|
20
18
|
Undefined = Object.new
|
21
19
|
|
22
20
|
YAKS_DEFAULT_OPTIONS = {
|
23
|
-
policy: DefaultPolicy.new,
|
24
|
-
profile_registry: NullProfileRegistry.new,
|
25
|
-
rel_registry: NullRelRegistry.new,
|
26
21
|
singular_links: [:self, :profile]
|
27
22
|
}
|
28
23
|
|
29
|
-
|
30
|
-
def
|
31
|
-
|
32
|
-
return Hamster::EmptyHash if object.nil?
|
33
|
-
Hamster.hash(object)
|
34
|
-
end
|
35
|
-
|
36
|
-
def List(*entries)
|
37
|
-
case entries.size
|
38
|
-
when 0
|
39
|
-
Hamster::EmptyList
|
40
|
-
when 1
|
41
|
-
if entries.first.respond_to? :to_list
|
42
|
-
entries.first.to_list
|
43
|
-
else
|
44
|
-
Hamster.list(*entries.compact)
|
45
|
-
end
|
46
|
-
else
|
47
|
-
Hamster.list(*entries)
|
48
|
-
end
|
24
|
+
class << self
|
25
|
+
def new(&blk)
|
26
|
+
Yaks::Config.new(&blk)
|
49
27
|
end
|
50
28
|
end
|
51
|
-
extend ClassMethods
|
52
29
|
|
53
30
|
end
|
54
31
|
|
@@ -64,10 +41,11 @@ require 'yaks/mapper/has_one'
|
|
64
41
|
require 'yaks/mapper/has_many'
|
65
42
|
require 'yaks/mapper/config'
|
66
43
|
require 'yaks/mapper/class_methods'
|
67
|
-
require 'yaks/mapper/map_links'
|
68
44
|
require 'yaks/mapper'
|
69
45
|
require 'yaks/collection_mapper'
|
70
46
|
|
71
47
|
require 'yaks/serializer'
|
72
|
-
require 'yaks/
|
73
|
-
require 'yaks/
|
48
|
+
require 'yaks/serializer/hal'
|
49
|
+
require 'yaks/serializer/json_api'
|
50
|
+
require 'yaks/serializer/collection_json'
|
51
|
+
require 'yaks/config'
|
data/notes.org
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
0.4
|
2
|
+
|
3
|
+
* DONE Get rid of profile/rel registry, use policy instead
|
4
|
+
* DONE pass around policy explicitly instead of through options
|
5
|
+
* DONE introduce name/type separate from profile
|
6
|
+
** DONE mapper
|
7
|
+
** DONE Resource
|
8
|
+
* DONE allow setting rel types directly on associations, with fallback to policy
|
9
|
+
* DONE switch to hash-based init of Resource to make it more extensible
|
10
|
+
* DONE add Resource#type
|
11
|
+
* DONE not 100% happy yet about nameing of mapper#mapper_name / config#name. Maybe use `type` across the board?
|
12
|
+
* DONE Fix JsonAPISerializer
|
13
|
+
* top-level automatic links, e.g. for self and profile
|
14
|
+
* make HAL plural/singular links configurable from the Yaks.new
|
15
|
+
* make primitivize configuration instance based, not global
|
16
|
+
* Have JsonApi add self links as href: attributes
|
17
|
+
* Move examples to acceptance tests
|
18
|
+
* Select mapper based on content type
|
19
|
+
* move to 100% mutcov
|
20
|
+
|
21
|
+
pre 0.5
|
22
|
+
|
23
|
+
* CURIES/namespaces
|
24
|
+
|
25
|
+
Ticketsolve::Api::Yaks = ::Yaks.new do
|
26
|
+
policy do
|
27
|
+
def derive...
|
28
|
+
end
|
29
|
+
|
30
|
+
hal_options.plural_link '...'
|
31
|
+
|
32
|
+
primitivize Date, Time do |o|
|
33
|
+
o.iso8601
|
34
|
+
end
|
35
|
+
|
36
|
+
rel_template "http://literature.example.com/rel/#{association_name}"
|
37
|
+
|
38
|
+
link :self, "http://api.com/{key}/{id}"
|
39
|
+
link :profile, "http://api.com/profile/{key}"
|
40
|
+
|
41
|
+
# and/or
|
42
|
+
derive_rel_from_association do |mapper, association|
|
43
|
+
"http://literature.example.com/rel/#{association.name}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
* DONE 59 lib/yaks/mapper.rb
|
50
|
+
* DONE 92 lib/yaks/mapper/link.rb
|
51
|
+
* DONE 37 lib/yaks/mapper/association.rb
|
52
|
+
* DONE 3 lib/yaks/version.rb
|
53
|
+
* DONE 13 lib/yaks/mapper/has_many.rb
|
54
|
+
* DONE 9 lib/yaks/mapper/has_one.rb
|
55
|
+
* DONE 79 lib/yaks/config.rb
|
56
|
+
* 79 lib/yaks/mapper/config.rb
|
57
|
+
* 73 lib/yaks.rb
|
58
|
+
* DONE 72 lib/yaks/util.rb
|
59
|
+
* DONE 65 lib/yaks/collection_resource.rb
|
60
|
+
* 59 lib/yaks/json_api_serializer.rb
|
61
|
+
* 59 lib/yaks/hal_serializer.rb
|
62
|
+
* 43 lib/yaks/primitivize.rb
|
63
|
+
* 37 lib/yaks/mapper/class_methods.rb
|
64
|
+
* DONE 33 lib/yaks/collection_mapper.rb
|
65
|
+
* 28 lib/yaks/null_resource.rb
|
66
|
+
* DONE 27 lib/yaks/resource.rb
|
67
|
+
* 25 lib/yaks/resource/link.rb
|
68
|
+
* DONE 23 lib/yaks/fp.rb
|
69
|
+
* 22 lib/yaks/serializer.rb
|
70
|
+
* 15 lib/yaks/shared_options.rb
|
71
|
+
* 15 lib/yaks/default_policy.rb
|
72
|
+
* 10 lib/yaks/mapper/map_links.rb
|
data/shaved_yak.gif
ADDED
Binary file
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'yaml'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
require_relative './models'
|
6
|
+
|
7
|
+
RSpec.shared_examples_for 'JSON output format' do |yaks, format, name|
|
8
|
+
let(:input) { load_yaml_fixture name }
|
9
|
+
let(:output) { load_json_fixture "#{name}.#{format}" }
|
10
|
+
|
11
|
+
subject { yaks.serialize(input) }
|
12
|
+
|
13
|
+
it { should eql output }
|
14
|
+
end
|
15
|
+
|
16
|
+
RSpec.describe Yaks::Serializer::Hal do
|
17
|
+
yaks_rel_template = Yaks.new do
|
18
|
+
rel_template "http://literature.example.com/rel/{association_name}"
|
19
|
+
end
|
20
|
+
|
21
|
+
yaks_policy_dsl = Yaks.new do
|
22
|
+
derive_rel_from_association do |mapper, association|
|
23
|
+
"http://literature.example.com/rel/#{association.name}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
include_examples 'JSON output format' , yaks_rel_template , :hal , 'confucius'
|
28
|
+
include_examples 'JSON output format' , yaks_policy_dsl , :hal , 'confucius'
|
29
|
+
end
|
30
|
+
|
31
|
+
RSpec.describe Yaks::Serializer::JsonApi do
|
32
|
+
config = Yaks.new do
|
33
|
+
default_format :json_api
|
34
|
+
end
|
35
|
+
|
36
|
+
include_examples 'JSON output format' , config , :json_api , 'confucius'
|
37
|
+
end
|
38
|
+
|
39
|
+
RSpec.describe Yaks::Serializer::CollectionJson do
|
40
|
+
config = Yaks.new do
|
41
|
+
default_format :collection_json
|
42
|
+
mapper_namespace Youtypeitwepostit
|
43
|
+
end
|
44
|
+
|
45
|
+
include_examples 'JSON output format' , config , :collection , 'youtypeitwepostit'
|
46
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'anima'
|
2
|
+
|
3
|
+
class Scholar
|
4
|
+
include Anima.new(:id, :name, :pinyin, :latinized, :works)
|
5
|
+
end
|
6
|
+
|
7
|
+
class Work
|
8
|
+
include Anima.new(:id, :chinese_name, :english_name)
|
9
|
+
end
|
10
|
+
|
11
|
+
class LiteratureBaseMapper < Yaks::Mapper
|
12
|
+
link :profile, 'http://literature.example.com/profiles/{mapper_name}'
|
13
|
+
link :self, 'http://literature.example.com/{mapper_name}/{id}'
|
14
|
+
end
|
15
|
+
|
16
|
+
class ScholarMapper < LiteratureBaseMapper
|
17
|
+
attributes :id, :name, :pinyin, :latinized
|
18
|
+
has_many :works
|
19
|
+
link :self, "http://literature.example.com/authors/{downcased_pinyin}"
|
20
|
+
|
21
|
+
def downcased_pinyin
|
22
|
+
object.pinyin.downcase
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class WorkMapper < LiteratureBaseMapper
|
27
|
+
attributes :id, :chinese_name, :english_name
|
28
|
+
end
|
@@ -1,28 +1,24 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe 'Mapping domain models to Resource objects' do
|
3
|
+
RSpec.describe 'Mapping domain models to Resource objects' do
|
4
4
|
include_context 'fixtures'
|
5
|
-
include_context 'shorthands'
|
6
5
|
|
7
6
|
subject { mapper.to_resource }
|
8
|
-
let(:mapper) { FriendMapper.new(john) }
|
9
|
-
|
7
|
+
let(:mapper) { FriendMapper.new(john, policy: Yaks::DefaultPolicy.new, env: {}) }
|
10
8
|
|
11
9
|
it { should be_a Yaks::Resource }
|
12
|
-
its(:
|
13
|
-
its(:
|
14
|
-
|
15
|
-
resource_link[:copyright, '/api/copyright/2024']
|
16
|
-
)}
|
10
|
+
its(:type) { should eql 'friend' }
|
11
|
+
its(:attributes) { should eql(id: 1, name: 'john') }
|
12
|
+
its(:links) { should eql [ Yaks::Resource::Link.new(:copyright, '/api/copyright/2024', {}) ] }
|
17
13
|
|
18
14
|
its(:subresources) {
|
19
|
-
should eq
|
20
|
-
"rel:src=friend&dest=pet_peeve" =>
|
15
|
+
should eq(
|
16
|
+
"rel:src=friend&dest=pet_peeve" => Yaks::Resource.new(type:'pet_peeve', attributes: {id: 4, type: 'parsing with regexps'}),
|
21
17
|
"rel:src=friend&dest=pets" => Yaks::CollectionResource.new(
|
22
|
-
|
23
|
-
[
|
24
|
-
|
25
|
-
|
18
|
+
type: 'pet',
|
19
|
+
members: [
|
20
|
+
Yaks::Resource.new(type: 'pet', attributes: {:id => 2, :species => "dog", :name => "boingboing"}),
|
21
|
+
Yaks::Resource.new(type: 'pet', attributes: {:id => 3, :species => "cat", :name => "wassup"})
|
26
22
|
]
|
27
23
|
)
|
28
24
|
)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
{
|
2
|
+
"id": 9,
|
3
|
+
"name": "孔子",
|
4
|
+
"pinyin": "Kongzi",
|
5
|
+
"latinized": "Confucius",
|
6
|
+
"_links": {
|
7
|
+
"self": { "href": "http://literature.example.com/authors/kongzi" },
|
8
|
+
"profile": { "href": "http://literature.example.com/profiles/scholar" }
|
9
|
+
},
|
10
|
+
"_embedded": {
|
11
|
+
"http://literature.example.com/rel/works": [
|
12
|
+
{
|
13
|
+
"id": 11,
|
14
|
+
"chinese_name": "論語",
|
15
|
+
"english_name": "Analects",
|
16
|
+
"_links": {
|
17
|
+
"self": { "href": "http://literature.example.com/work/11" },
|
18
|
+
"profile": { "href": "http://literature.example.com/profiles/work" }
|
19
|
+
}
|
20
|
+
}
|
21
|
+
]
|
22
|
+
}
|
23
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"scholars": [
|
3
|
+
{
|
4
|
+
"id": 9,
|
5
|
+
"name": "孔子",
|
6
|
+
"pinyin": "Kongzi",
|
7
|
+
"latinized": "Confucius",
|
8
|
+
"links": {
|
9
|
+
"works": [11]
|
10
|
+
}
|
11
|
+
}
|
12
|
+
],
|
13
|
+
"linked": {
|
14
|
+
"works": [
|
15
|
+
{
|
16
|
+
"id": 11,
|
17
|
+
"chinese_name": "論語",
|
18
|
+
"english_name": "Analects"
|
19
|
+
}
|
20
|
+
]
|
21
|
+
}
|
22
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
{
|
2
|
+
"id": 1,
|
3
|
+
"name": "john",
|
4
|
+
"_links": {
|
5
|
+
"copyright": [
|
6
|
+
{
|
7
|
+
"href": "/api/copyright/2024"
|
8
|
+
}
|
9
|
+
]
|
10
|
+
},
|
11
|
+
"_embedded": {
|
12
|
+
"http://api.mysuperfriends.com/pet_peeve": {
|
13
|
+
"id": 4,
|
14
|
+
"type": "parsing with regexps"
|
15
|
+
},
|
16
|
+
"http://api.mysuperfriends.com/pets": [
|
17
|
+
{
|
18
|
+
"id": 2,
|
19
|
+
"name": "boingboing",
|
20
|
+
"species": "dog"
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"id": 3,
|
24
|
+
"name": "wassup",
|
25
|
+
"species": "cat"
|
26
|
+
}
|
27
|
+
]
|
28
|
+
}
|
29
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
{
|
2
|
+
"collection" :
|
3
|
+
{
|
4
|
+
"version" : "1.0",
|
5
|
+
"href" : "http://www.youtypeitwepostit.com/api/",
|
6
|
+
|
7
|
+
"items" :
|
8
|
+
[
|
9
|
+
{
|
10
|
+
"href": "http://www.youtypeitwepostit.com/api/12091295723803341",
|
11
|
+
"data": [
|
12
|
+
{
|
13
|
+
"name": "text",
|
14
|
+
"value": "massage"
|
15
|
+
},
|
16
|
+
{
|
17
|
+
"name": "date_posted",
|
18
|
+
"value": "2014-05-29T07:56:58.035Z"
|
19
|
+
}
|
20
|
+
],
|
21
|
+
"links" :
|
22
|
+
[
|
23
|
+
{ "rel": "profile", "href" : "http://www.youtypeitwepostit.com/profiles/message" }
|
24
|
+
]
|
25
|
+
},
|
26
|
+
{
|
27
|
+
"href": "http://www.youtypeitwepostit.com/api/613856331910938",
|
28
|
+
"data": [
|
29
|
+
{
|
30
|
+
"name": "text",
|
31
|
+
"value": "Squid!"
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"name": "date_posted",
|
35
|
+
"value": "2013-03-28T21:51:08.406Z"
|
36
|
+
}
|
37
|
+
],
|
38
|
+
"links" :
|
39
|
+
[
|
40
|
+
{ "rel": "profile", "href" : "http://www.youtypeitwepostit.com/profiles/message" }
|
41
|
+
]
|
42
|
+
}
|
43
|
+
]
|
44
|
+
}
|
45
|
+
}
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'pathname'
|
2
|
+
require 'rspec/its'
|
2
3
|
|
3
4
|
ROOT = Pathname(__FILE__).join('../..')
|
4
5
|
|
@@ -13,9 +14,19 @@ require_relative 'support/pet_mapper'
|
|
13
14
|
require_relative 'support/pet_peeve_mapper'
|
14
15
|
require_relative 'support/friends_mapper'
|
15
16
|
require_relative 'support/fixtures'
|
16
|
-
require_relative 'support/shorthands'
|
17
17
|
require_relative 'support/shared_contexts'
|
18
|
+
require_relative 'support/youtypeit_models_mappers'
|
18
19
|
|
19
20
|
def load_json_fixture(name)
|
20
21
|
JSON.parse(ROOT.join('spec/json', name + '.json').read)
|
21
22
|
end
|
23
|
+
|
24
|
+
def load_yaml_fixture(name)
|
25
|
+
YAML.load(ROOT.join('spec/yaml', name + '.yaml').read)
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec.configure do |rspec|
|
29
|
+
rspec.backtrace_exclusion_patterns = [] if ENV['FULLSTACK']
|
30
|
+
#rspec.disable_monkey_patching!
|
31
|
+
rspec.raise_errors_for_deprecations!
|
32
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
shared_context 'collection resource' do
|
2
|
-
let(:resource) { Yaks::CollectionResource.new(links, members) }
|
2
|
+
let(:resource) { Yaks::CollectionResource.new(links: links, members: members) }
|
3
3
|
let(:links) { [] }
|
4
4
|
let(:members) { [] }
|
5
5
|
end
|
@@ -23,25 +23,22 @@ shared_context 'plant collection resource' do
|
|
23
23
|
|
24
24
|
let(:plain_grass) do
|
25
25
|
Yaks::Resource.new(
|
26
|
-
{name: "Plain grass", type: "grass"},
|
27
|
-
[plain_grass_self_link, plant_profile_link]
|
28
|
-
{}
|
26
|
+
attributes: {name: "Plain grass", type: "grass"},
|
27
|
+
links: [plain_grass_self_link, plant_profile_link]
|
29
28
|
)
|
30
29
|
end
|
31
30
|
|
32
31
|
let(:oak) do
|
33
32
|
Yaks::Resource.new(
|
34
|
-
{name: "Oak", type: "tree"},
|
35
|
-
[oak_self_link, plant_profile_link],
|
36
|
-
{}
|
33
|
+
attributes: {name: "Oak", type: "tree"},
|
34
|
+
links: [oak_self_link, plant_profile_link],
|
37
35
|
)
|
38
36
|
end
|
39
37
|
|
40
38
|
let(:passiflora) do
|
41
39
|
Yaks::Resource.new(
|
42
|
-
{name: "Passiflora", type: "flower"},
|
43
|
-
[passiflora_self_link, plant_profile_link],
|
44
|
-
{}
|
40
|
+
attributes: {name: "Passiflora", type: "flower"},
|
41
|
+
links: [passiflora_self_link, plant_profile_link],
|
45
42
|
)
|
46
43
|
end
|
47
44
|
end
|