yaks 0.3.1 → 0.4.0.rc1
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/.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
|