yaks 0.6.0.alpha.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +46 -0
- data/lib/yaks/attributes.rb +45 -0
- data/lib/yaks/collection_resource.rb +1 -45
- data/lib/yaks/config/dsl.rb +15 -6
- data/lib/yaks/config.rb +1 -1
- data/lib/yaks/configurable.rb +20 -0
- data/lib/yaks/default_policy.rb +0 -8
- data/lib/yaks/errors.rb +3 -0
- data/lib/yaks/format/hal.rb +13 -2
- data/lib/yaks/format/halo.rb +29 -0
- data/lib/yaks/mapper/association.rb +18 -13
- data/lib/yaks/mapper/association_mapper.rb +1 -1
- data/lib/yaks/mapper/attribute.rb +1 -3
- data/lib/yaks/mapper/class_methods.rb +24 -16
- data/lib/yaks/mapper/config.rb +13 -28
- data/lib/yaks/mapper/control.rb +38 -0
- data/lib/yaks/mapper/has_many.rb +4 -8
- data/lib/yaks/mapper/link.rb +10 -2
- data/lib/yaks/mapper.rb +11 -2
- data/lib/yaks/resource/control.rb +11 -0
- data/lib/yaks/resource/link.rb +1 -7
- data/lib/yaks/resource.rb +9 -13
- data/lib/yaks/runner.rb +2 -4
- data/lib/yaks/serializer.rb +12 -0
- data/lib/yaks/stateful_builder.rb +54 -0
- data/lib/yaks/version.rb +1 -1
- data/lib/yaks.rb +16 -7
- data/spec/acceptance/acceptance_spec.rb +14 -4
- data/spec/acceptance/models.rb +9 -0
- data/spec/integration/map_to_resource_spec.rb +1 -1
- data/spec/json/confucius.halo.json +80 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/shared_contexts.rb +1 -1
- data/spec/unit/yaks/attributes_spec.rb +65 -0
- data/spec/unit/yaks/collection_mapper_spec.rb +1 -1
- data/spec/unit/yaks/collection_resource_spec.rb +7 -25
- data/spec/unit/yaks/config/dsl_spec.rb +5 -0
- data/spec/unit/yaks/config_spec.rb +2 -1
- data/spec/unit/yaks/configurable_spec.rb +25 -0
- data/spec/unit/yaks/default_policy_spec.rb +1 -7
- data/spec/unit/yaks/format/collection_json_spec.rb +1 -1
- data/spec/unit/yaks/format/hal_spec.rb +2 -2
- data/spec/unit/yaks/format/html_spec.rb +5 -0
- data/spec/unit/yaks/format/json_api_spec.rb +1 -1
- data/spec/unit/yaks/format_spec.rb +1 -5
- data/spec/unit/yaks/mapper/association_mapper_spec.rb +2 -2
- data/spec/unit/yaks/mapper/association_spec.rb +27 -3
- data/spec/unit/yaks/mapper/class_methods_spec.rb +17 -1
- data/spec/unit/yaks/mapper/config_spec.rb +16 -8
- data/spec/unit/yaks/mapper/has_many_spec.rb +15 -2
- data/spec/unit/yaks/mapper/has_one_spec.rb +1 -1
- data/spec/unit/yaks/mapper/link_spec.rb +12 -2
- data/spec/unit/yaks/mapper_spec.rb +51 -22
- data/spec/unit/yaks/resource/link_spec.rb +2 -1
- data/spec/unit/yaks/resource_spec.rb +16 -9
- data/spec/unit/yaks/runner_spec.rb +22 -2
- data/spec/unit/yaks/serializer_spec.rb +20 -0
- data/spec/unit/yaks/stateful_builder_spec.rb +41 -0
- data/yaks.gemspec +1 -0
- metadata +39 -11
- data/lib/yaks/fp/hash_updatable.rb +0 -19
- data/lib/yaks/fp/updatable.rb +0 -17
- data/spec/unit/yaks/fp/hash_updatable_spec.rb +0 -22
- data/spec/unit/yaks/fp/updatable_spec.rb +0 -22
data/lib/yaks/runner.rb
CHANGED
@@ -56,7 +56,7 @@ module Yaks
|
|
56
56
|
|
57
57
|
def primitivizer
|
58
58
|
->(input) do
|
59
|
-
if format_class.serializer
|
59
|
+
if format_class.serializer.equal? :json
|
60
60
|
primitivize.call(input)
|
61
61
|
else
|
62
62
|
input
|
@@ -73,9 +73,7 @@ module Yaks
|
|
73
73
|
memoize :format_name
|
74
74
|
|
75
75
|
def serializer
|
76
|
-
serializers.fetch(format_class.serializer)
|
77
|
-
policy.serializer_for_format(format_class)
|
78
|
-
end
|
76
|
+
serializers.fetch(format_class.serializer)
|
79
77
|
end
|
80
78
|
memoize :serializer
|
81
79
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Yaks
|
2
|
+
module Serializer
|
3
|
+
def self.register(format, serializer)
|
4
|
+
raise "Serializer for #{format} already registered" if all.key? format
|
5
|
+
all[format] = serializer
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.all
|
9
|
+
@serializers ||= {json: JSON.method(:pretty_generate)}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Yaks
|
2
|
+
# State monad-ish thing.
|
3
|
+
#
|
4
|
+
# Generate a DSL syntax for immutable classes.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
#
|
8
|
+
# # This code
|
9
|
+
# Control.create(:search)
|
10
|
+
# .method("POST")
|
11
|
+
# .href("/search")
|
12
|
+
#
|
13
|
+
# # Can be written as
|
14
|
+
# StatefulBuilder.new(Control, [:method, :href]).create(:search) do
|
15
|
+
# method "POST"
|
16
|
+
# href "/search"
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
class StatefulBuilder < BasicObject
|
20
|
+
def create(*args, &block)
|
21
|
+
@state = @klass.create(*args)
|
22
|
+
instance_eval(&block)
|
23
|
+
@state
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(klass, methods)
|
27
|
+
@klass = klass
|
28
|
+
StatefulMethods.new(methods).send(:extend_object, self)
|
29
|
+
end
|
30
|
+
|
31
|
+
def validate_state(method_name, args)
|
32
|
+
unless @state.instance_of?(@klass)
|
33
|
+
::Kernel.raise(
|
34
|
+
IllegalState,
|
35
|
+
"#{@klass}##{method_name}(#{args.map(&:inspect).join(', ')}) "\
|
36
|
+
"returned #{@state.inspect}. Expected instance of #{@klass}"
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class StatefulMethods < ::Module
|
42
|
+
def initialize(methods)
|
43
|
+
methods.each { |name| define_stateful_method(name) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def define_stateful_method(method_name)
|
47
|
+
define_method method_name do |*args, &block|
|
48
|
+
@state = @state.public_send(method_name, *args, &block)
|
49
|
+
validate_state(method_name, args)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/yaks/version.rb
CHANGED
data/lib/yaks.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'forwardable'
|
4
4
|
require 'set'
|
5
5
|
require 'pathname'
|
6
|
+
require 'json'
|
6
7
|
|
7
8
|
require 'anima'
|
8
9
|
require 'concord'
|
@@ -11,11 +12,13 @@ require 'uri_template'
|
|
11
12
|
require 'rack/accept'
|
12
13
|
|
13
14
|
require 'yaks/util'
|
15
|
+
require 'yaks/configurable'
|
14
16
|
require 'yaks/fp'
|
15
|
-
require 'yaks/fp/updatable'
|
16
|
-
require 'yaks/fp/hash_updatable'
|
17
17
|
require 'yaks/fp/callable'
|
18
18
|
require 'yaks/primitivize'
|
19
|
+
require 'yaks/attributes'
|
20
|
+
require 'yaks/stateful_builder'
|
21
|
+
require 'yaks/errors'
|
19
22
|
|
20
23
|
require 'yaks/default_policy'
|
21
24
|
|
@@ -41,19 +44,25 @@ require 'yaks/null_resource'
|
|
41
44
|
require 'yaks/resource/link'
|
42
45
|
require 'yaks/collection_resource'
|
43
46
|
|
44
|
-
require 'yaks/mapper/class_methods'
|
45
|
-
require 'yaks/mapper'
|
46
|
-
require 'yaks/mapper/attribute'
|
47
|
-
require 'yaks/mapper/link'
|
48
47
|
require 'yaks/mapper/association'
|
49
|
-
require 'yaks/mapper/association_mapper'
|
50
48
|
require 'yaks/mapper/has_one'
|
51
49
|
require 'yaks/mapper/has_many'
|
50
|
+
require 'yaks/mapper/attribute'
|
51
|
+
require 'yaks/mapper/link'
|
52
|
+
require 'yaks/mapper/control'
|
52
53
|
require 'yaks/mapper/config'
|
54
|
+
require 'yaks/mapper/class_methods'
|
55
|
+
require 'yaks/mapper'
|
56
|
+
require 'yaks/mapper/association_mapper'
|
53
57
|
require 'yaks/collection_mapper'
|
54
58
|
|
59
|
+
require 'yaks/resource/control'
|
60
|
+
|
61
|
+
require 'yaks/serializer'
|
62
|
+
|
55
63
|
require 'yaks/format'
|
56
64
|
require 'yaks/format/hal'
|
65
|
+
require 'yaks/format/halo'
|
57
66
|
require 'yaks/format/json_api'
|
58
67
|
require 'yaks/format/collection_json'
|
59
68
|
|
@@ -6,7 +6,7 @@ require 'acceptance/json_shared_examples'
|
|
6
6
|
RSpec.describe Yaks::Format::Hal do
|
7
7
|
yaks_rel_template = Yaks.new do
|
8
8
|
format_options :hal, plural_links: ['http://literature.example.com/rels/quotes']
|
9
|
-
rel_template "http://literature.example.com/rel/{
|
9
|
+
rel_template "http://literature.example.com/rel/{rel}"
|
10
10
|
skip :serialize
|
11
11
|
end
|
12
12
|
|
@@ -18,8 +18,18 @@ RSpec.describe Yaks::Format::Hal do
|
|
18
18
|
skip :serialize
|
19
19
|
end
|
20
20
|
|
21
|
-
include_examples 'JSON output format'
|
22
|
-
include_examples 'JSON output format'
|
21
|
+
include_examples 'JSON output format', yaks_rel_template, :hal, 'confucius'
|
22
|
+
include_examples 'JSON output format', yaks_policy_dsl, :hal, 'confucius'
|
23
|
+
end
|
24
|
+
|
25
|
+
RSpec.describe Yaks::Format::Halo do
|
26
|
+
yaks = Yaks.new do
|
27
|
+
default_format :halo
|
28
|
+
rel_template "http://literature.example.com/rel/{rel}"
|
29
|
+
skip :serialize
|
30
|
+
end
|
31
|
+
|
32
|
+
include_examples 'JSON output format', yaks, :halo, 'confucius'
|
23
33
|
end
|
24
34
|
|
25
35
|
RSpec.describe Yaks::Format::JsonAPI do
|
@@ -28,7 +38,7 @@ RSpec.describe Yaks::Format::JsonAPI do
|
|
28
38
|
skip :serialize
|
29
39
|
end
|
30
40
|
|
31
|
-
include_examples 'JSON output format'
|
41
|
+
include_examples 'JSON output format', config, :json_api, 'confucius'
|
32
42
|
end
|
33
43
|
|
34
44
|
RSpec.describe Yaks::Format::CollectionJson do
|
data/spec/acceptance/models.rb
CHANGED
@@ -28,6 +28,15 @@ class ScholarMapper < LiteratureBaseMapper
|
|
28
28
|
link 'http://literature.example.com/rels/quotes', 'http://literature.example.com/quotes/?author={downcased_pinyin}&q={query}', expand: [:downcased_pinyin], title: 'Search for quotes'
|
29
29
|
link :self, 'http://literature.example.com/authors/{downcased_pinyin}'
|
30
30
|
|
31
|
+
control :search do
|
32
|
+
title 'Find a Scholar'
|
33
|
+
method 'POST'
|
34
|
+
media_type 'application/x-www-form-urlencoded'
|
35
|
+
|
36
|
+
field :name, label: 'Scholar Name', type: 'text'
|
37
|
+
field :pinyin, label: 'Hanyu Pinyin', type: 'text'
|
38
|
+
end
|
39
|
+
|
31
40
|
def downcased_pinyin
|
32
41
|
object.pinyin.downcase
|
33
42
|
end
|
@@ -10,7 +10,7 @@ RSpec.describe 'Mapping domain models to Resource objects' do
|
|
10
10
|
it { should be_a Yaks::Resource }
|
11
11
|
its(:type) { should eql 'friend' }
|
12
12
|
its(:attributes) { should eql(id: 1, name: 'john') }
|
13
|
-
its(:links) { should eql [ Yaks::Resource::Link.new(:copyright, '/api/copyright/2024'
|
13
|
+
its(:links) { should eql [ Yaks::Resource::Link.new(rel: :copyright, uri: '/api/copyright/2024') ] }
|
14
14
|
|
15
15
|
its(:subresources) {
|
16
16
|
should eq(
|
@@ -0,0 +1,80 @@
|
|
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
|
+
"http://literature.example.com/rels/quotes": {
|
10
|
+
"href": "http://literature.example.com/quotes/?author=kongzi&q={query}",
|
11
|
+
"templated": true,
|
12
|
+
"title": "Search for quotes"
|
13
|
+
}
|
14
|
+
},
|
15
|
+
"_embedded": {
|
16
|
+
"http://literature.example.com/rel/works": [
|
17
|
+
{
|
18
|
+
"id": 11,
|
19
|
+
"chinese_name": "論語",
|
20
|
+
"english_name": "Analects",
|
21
|
+
"_links": {
|
22
|
+
"self": { "href": "http://literature.example.com/work/11" },
|
23
|
+
"profile": { "href": "http://literature.example.com/profiles/work" }
|
24
|
+
},
|
25
|
+
"_embedded": {
|
26
|
+
"http://literature.example.com/rel/quotes": [
|
27
|
+
{
|
28
|
+
"id": 17,
|
29
|
+
"chinese": "廄焚。子退朝,曰:“傷人乎?” 不問馬。"
|
30
|
+
},
|
31
|
+
{
|
32
|
+
"id": 18,
|
33
|
+
"chinese": "子曰:“其恕乎!己所不欲、勿施於人。”"
|
34
|
+
}
|
35
|
+
],
|
36
|
+
"http://literature.example.com/rel/era": {
|
37
|
+
"id": 99,
|
38
|
+
"name": "Zhou Dynasty"
|
39
|
+
}
|
40
|
+
}
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"id": 12,
|
44
|
+
"chinese_name": "易經",
|
45
|
+
"english_name": "Commentaries to the Yi-jing",
|
46
|
+
"_links": {
|
47
|
+
"self": { "href": "http://literature.example.com/work/12" },
|
48
|
+
"profile": { "href": "http://literature.example.com/profiles/work" }
|
49
|
+
},
|
50
|
+
"_embedded": {
|
51
|
+
"http://literature.example.com/rel/quotes": [],
|
52
|
+
"http://literature.example.com/rel/era": null
|
53
|
+
}
|
54
|
+
}
|
55
|
+
]
|
56
|
+
},
|
57
|
+
"_controls": {
|
58
|
+
"search": {
|
59
|
+
"name": "search",
|
60
|
+
"href": null,
|
61
|
+
"title": "Find a Scholar",
|
62
|
+
"method": "POST",
|
63
|
+
"media_type": "application/x-www-form-urlencoded",
|
64
|
+
"fields": [
|
65
|
+
{
|
66
|
+
"name": "name",
|
67
|
+
"label": "Scholar Name",
|
68
|
+
"type": "text",
|
69
|
+
"value": null
|
70
|
+
},
|
71
|
+
{
|
72
|
+
"name": "pinyin",
|
73
|
+
"label": "Hanyu Pinyin",
|
74
|
+
"type": "text",
|
75
|
+
"value": null
|
76
|
+
}
|
77
|
+
]
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'rspec/its'
|
2
2
|
require 'bogus/rspec'
|
3
|
+
require 'timeout'
|
3
4
|
|
4
5
|
require 'yaks'
|
6
|
+
require 'yaks-html'
|
5
7
|
require 'virtus'
|
6
8
|
|
7
9
|
require 'fixture_helpers'
|
@@ -22,6 +24,9 @@ RSpec.configure do |rspec|
|
|
22
24
|
rspec.backtrace_exclusion_patterns = [] if ENV['FULLSTACK']
|
23
25
|
rspec.disable_monkey_patching!
|
24
26
|
rspec.raise_errors_for_deprecations!
|
27
|
+
rspec.around(:each) do |example|
|
28
|
+
Timeout.timeout(1, &example)
|
29
|
+
end
|
25
30
|
end
|
26
31
|
|
27
32
|
Bogus.configure do |bogus|
|
@@ -31,7 +31,7 @@ RSpec.shared_context 'plant collection resource' do
|
|
31
31
|
[ :oak , :self , 'http://api.example.com/plants/15/oak' ],
|
32
32
|
[ :passiflora , :self , 'http://api.example.com/plants/33/passiflora' ],
|
33
33
|
].each do |name, type, uri|
|
34
|
-
let(:"#{name}_#{type}_link") { Yaks::Resource::Link.new(type, uri
|
34
|
+
let(:"#{name}_#{type}_link") { Yaks::Resource::Link.new(rel: type, uri: uri) }
|
35
35
|
end
|
36
36
|
|
37
37
|
let(:plain_grass) do
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Yaks::Attributes do
|
4
|
+
subject { Class.new { include Yaks::Attributes.new(:foo, bar: 3) } }
|
5
|
+
|
6
|
+
it 'should have a hash-based constructor' do
|
7
|
+
expect(subject.new(foo: 3, bar: 4).bar).to equal 4
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should have defaults constructor' do
|
11
|
+
expect(subject.new(foo: 3).bar).to equal 3
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should allow updating through attribute methods' do
|
15
|
+
expect(subject.new(foo: 3).foo(4).to_h).to eql(foo: 4, bar: 3)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should add an #append_to method' do
|
19
|
+
expect(subject.new(foo: [6]).append_to(:foo, 7, 8).foo).to eql [6, 7, 8]
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with all defaults' do
|
23
|
+
subject { Class.new { include Yaks::Attributes.new(foo: 5, bar: 3) } }
|
24
|
+
|
25
|
+
it 'should be able to construct without arguments' do
|
26
|
+
expect(subject.new.to_h).to eql(foo: 5, bar: 3)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'without any defaults' do
|
31
|
+
subject { Class.new { include Yaks::Attributes.new(:foo, :bar) } }
|
32
|
+
|
33
|
+
it 'should allow setting all attributes' do
|
34
|
+
expect(subject.new(foo: 5, bar: 6).bar).to equal 6
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should expect all attributes' do
|
38
|
+
expect { subject.new(foo: 5) }.to raise_exception
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when extending' do
|
43
|
+
subject { Class.new(super()) { include attributes.add(baz: 7) } }
|
44
|
+
|
45
|
+
it 'should make the new attributes available' do
|
46
|
+
expect(subject.new(foo: 3, baz: 6).baz).to equal 6
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should make the old attributes available' do
|
50
|
+
expect(subject.new(foo: 3, baz: 6).foo).to equal 3
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'without any defaults' do
|
54
|
+
subject { Class.new(super()) { include attributes.add(:bax) } }
|
55
|
+
|
56
|
+
it 'should allow setting all attributes' do
|
57
|
+
expect(subject.new(foo: 5, bar: 6, bax: 7).bax).to equal 7
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should expect all attributes' do
|
61
|
+
expect { subject.new(foo: 5, bar: 6) }.to raise_exception
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -108,7 +108,7 @@ RSpec.describe Yaks::CollectionMapper do
|
|
108
108
|
it 'should map the links' do
|
109
109
|
expect(mapper.call(collection)).to eql Yaks::CollectionResource.new(
|
110
110
|
type: 'the_type',
|
111
|
-
links: [ Yaks::Resource::Link.new(:self, 'http://api.example.com/orders'
|
111
|
+
links: [ Yaks::Resource::Link.new(rel: :self, uri: 'http://api.example.com/orders') ],
|
112
112
|
attributes: { },
|
113
113
|
members: [],
|
114
114
|
collection_rel: 'rel:the_types'
|
@@ -21,14 +21,14 @@ RSpec.describe Yaks::CollectionResource do
|
|
21
21
|
{
|
22
22
|
type: 'order',
|
23
23
|
links: [
|
24
|
-
Yaks::Resource::Link.new('http://rels/summary', 'http://order/10/summary'
|
25
|
-
Yaks::Resource::Link.new(:profile, 'http://rels/collection'
|
24
|
+
Yaks::Resource::Link.new(rel: 'http://rels/summary', uri: 'http://order/10/summary'),
|
25
|
+
Yaks::Resource::Link.new(rel: :profile, uri: 'http://rels/collection')
|
26
26
|
],
|
27
27
|
attributes: { total: 10.00 },
|
28
28
|
members: [
|
29
29
|
Yaks::Resource.new(
|
30
30
|
type: 'order',
|
31
|
-
links: [Yaks::Resource::Link.new(:self, 'http://order/10'
|
31
|
+
links: [Yaks::Resource::Link.new(rel: :self, uri: 'http://order/10')],
|
32
32
|
attributes: { customer: 'John Doe', price: 10.00 }
|
33
33
|
)
|
34
34
|
],
|
@@ -38,40 +38,22 @@ RSpec.describe Yaks::CollectionResource do
|
|
38
38
|
|
39
39
|
its(:type) { should eql 'order' }
|
40
40
|
its(:links) { should eql [
|
41
|
-
Yaks::Resource::Link.new('http://rels/summary', 'http://order/10/summary'
|
42
|
-
Yaks::Resource::Link.new(:profile, 'http://rels/collection'
|
41
|
+
Yaks::Resource::Link.new(rel: 'http://rels/summary', uri: 'http://order/10/summary'),
|
42
|
+
Yaks::Resource::Link.new(rel: :profile, uri: 'http://rels/collection')
|
43
43
|
]
|
44
44
|
}
|
45
45
|
its(:attributes) { should eql( total: 10.00 ) }
|
46
46
|
its(:members) { should eql [
|
47
47
|
Yaks::Resource.new(
|
48
48
|
type: 'order',
|
49
|
-
links: [Yaks::Resource::Link.new(:self, 'http://order/10'
|
49
|
+
links: [Yaks::Resource::Link.new(rel: :self, uri: 'http://order/10')],
|
50
50
|
attributes: { customer: 'John Doe', price: 10.00 }
|
51
51
|
)
|
52
52
|
]
|
53
53
|
}
|
54
54
|
its(:collection_rel) { should eq 'http://api.example.org/rels/orders'}
|
55
55
|
|
56
|
-
its(:subresources) { should eql(
|
57
|
-
'http://api.example.org/rels/orders' => Yaks::CollectionResource.new(
|
58
|
-
type: 'order',
|
59
|
-
attributes: { total: 10.00 },
|
60
|
-
links: [
|
61
|
-
Yaks::Resource::Link.new('http://rels/summary', 'http://order/10/summary', {}),
|
62
|
-
Yaks::Resource::Link.new(:profile, 'http://rels/collection', {})
|
63
|
-
],
|
64
|
-
members: [
|
65
|
-
Yaks::Resource.new(
|
66
|
-
type: 'order',
|
67
|
-
links: [Yaks::Resource::Link.new(:self, 'http://order/10', {})],
|
68
|
-
attributes: { customer: 'John Doe', price: 10.00 }
|
69
|
-
)
|
70
|
-
],
|
71
|
-
collection_rel: 'http://api.example.org/rels/orders'
|
72
|
-
)
|
73
|
-
)
|
74
|
-
}
|
56
|
+
its(:subresources) { should eql({}) }
|
75
57
|
|
76
58
|
end
|
77
59
|
end
|
@@ -61,6 +61,11 @@ RSpec.describe Yaks::Config::DSL do
|
|
61
61
|
specify { expect(yaks_config.policy_options[:rel_template]).to eql 'rels:{rel}' }
|
62
62
|
end
|
63
63
|
|
64
|
+
describe '#serializer' do
|
65
|
+
configure { serializer(:json) { |i| "foo #{i}" } }
|
66
|
+
specify { expect(yaks_config.serializers[:json].call(7)).to eql 'foo 7' }
|
67
|
+
end
|
68
|
+
|
64
69
|
describe '#json_serializer' do
|
65
70
|
configure { json_serializer { |i| "foo #{i}" } }
|
66
71
|
specify { expect(yaks_config.serializers[:json].call(7)).to eql 'foo 7' }
|
@@ -14,7 +14,8 @@ RSpec.describe Yaks::Config do
|
|
14
14
|
its(:default_format) { should equal :hal }
|
15
15
|
its(:policy_class) { should < Yaks::DefaultPolicy }
|
16
16
|
its(:primitivize) { should be_a Yaks::Primitivize }
|
17
|
-
its(:serializers) { should eql(
|
17
|
+
its(:serializers) { should eql(Yaks::Serializer.all) }
|
18
|
+
its(:serializers) { should_not equal(Yaks::Serializer.all) }
|
18
19
|
its(:hooks) { should eql([]) }
|
19
20
|
|
20
21
|
it 'should have empty format options' do
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Yaks::Configurable do
|
4
|
+
class Creatable
|
5
|
+
def self.create(*args, &block)
|
6
|
+
["->", *args, block.call]
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
subject do
|
11
|
+
Class.new do
|
12
|
+
include Yaks::Attributes.new(foo: []), Yaks::Configurable
|
13
|
+
|
14
|
+
config_method :bar, append_to: :foo, create: Creatable
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should generate the config method' do
|
19
|
+
expect(
|
20
|
+
subject.new.bar(1,2,3) { 4 }
|
21
|
+
.bar(:baz) { :booz }
|
22
|
+
.foo
|
23
|
+
).to eql [["->", 1, 2, 3, 4], ["->", :baz, :booz]]
|
24
|
+
end
|
25
|
+
end
|
@@ -4,7 +4,7 @@ RSpec.describe Yaks::DefaultPolicy do
|
|
4
4
|
subject(:policy) { described_class.new( options ) }
|
5
5
|
|
6
6
|
let(:options) { {} }
|
7
|
-
let(:association) { Yaks::Mapper::HasMany.
|
7
|
+
let(:association) { Yaks::Mapper::HasMany.create('shoes') }
|
8
8
|
|
9
9
|
describe '#initialize' do
|
10
10
|
it 'should work without arguments' do
|
@@ -61,10 +61,4 @@ RSpec.describe Yaks::DefaultPolicy do
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
-
describe '#serializer_for_format' do
|
65
|
-
specify {
|
66
|
-
expect(policy.serializer_for_format(Yaks::Format::JsonAPI).call('foo' => [1,2])).to eql "{\n \"foo\": [\n 1,\n 2\n ]\n}"
|
67
|
-
}
|
68
|
-
end
|
69
|
-
|
70
64
|
end
|
@@ -13,7 +13,7 @@ RSpec.describe Yaks::Format::CollectionJson do
|
|
13
13
|
let(:resource) {
|
14
14
|
Yaks::Resource.new(
|
15
15
|
attributes: {foo: 'fooval', bar: 'barval'},
|
16
|
-
links: [Yaks::Resource::Link.new('the_rel', 'the_uri'
|
16
|
+
links: [Yaks::Resource::Link.new(rel: 'the_rel', uri: 'the_uri')]
|
17
17
|
)
|
18
18
|
}
|
19
19
|
|
@@ -18,8 +18,8 @@ RSpec.describe Yaks::Format::Hal do
|
|
18
18
|
Yaks::Resource.new(
|
19
19
|
attributes: {foo: 'fooval', bar: 'barval'},
|
20
20
|
links: [
|
21
|
-
Yaks::Resource::Link.new('my_plural_rel', 'the_uri1'
|
22
|
-
Yaks::Resource::Link.new('my_plural_rel', 'the_uri2'
|
21
|
+
Yaks::Resource::Link.new(rel: 'my_plural_rel', uri: 'the_uri1'),
|
22
|
+
Yaks::Resource::Link.new(rel: 'my_plural_rel', uri: 'the_uri2')
|
23
23
|
]
|
24
24
|
)
|
25
25
|
}
|
@@ -27,11 +27,7 @@ RSpec.describe Yaks::Format do
|
|
27
27
|
|
28
28
|
describe '.mime_types' do
|
29
29
|
specify do
|
30
|
-
expect(Yaks::Format.mime_types).to eql(
|
31
|
-
collection_json: "application/vnd.collection+json",
|
32
|
-
hal: "application/hal+json",
|
33
|
-
json_api: "application/vnd.api+json"
|
34
|
-
)
|
30
|
+
expect(Yaks::Format.mime_types.values_at(:collection_json, :hal, :json_api)).to eql(["application/vnd.collection+json", "application/hal+json", "application/vnd.api+json"])
|
35
31
|
end
|
36
32
|
end
|
37
33
|
end
|
@@ -26,8 +26,8 @@ RSpec.describe Yaks::Mapper::AssociationMapper do
|
|
26
26
|
expect(association_mapper.call(Yaks::Resource.new)).to eql Yaks::Resource.new(
|
27
27
|
links: [
|
28
28
|
Yaks::Resource::Link.new(
|
29
|
-
'rels:the_rel',
|
30
|
-
'http://this/is_where_the_associated_thing_can_be_found'
|
29
|
+
rel: 'rels:the_rel',
|
30
|
+
uri: 'http://this/is_where_the_associated_thing_can_be_found'
|
31
31
|
)
|
32
32
|
]
|
33
33
|
)
|
@@ -6,7 +6,7 @@ RSpec.describe Yaks::Mapper::Association do
|
|
6
6
|
subject(:association) do
|
7
7
|
described_class.new(
|
8
8
|
name: name,
|
9
|
-
|
9
|
+
item_mapper: mapper,
|
10
10
|
rel: rel,
|
11
11
|
href: href,
|
12
12
|
link_if: link_if
|
@@ -20,13 +20,13 @@ RSpec.describe Yaks::Mapper::Association do
|
|
20
20
|
let(:link_if) { Yaks::Undefined }
|
21
21
|
|
22
22
|
its(:name) { should equal :shoes }
|
23
|
-
its(:
|
23
|
+
its(:item_mapper) { should equal Yaks::Mapper }
|
24
24
|
|
25
25
|
context 'with a minimal constructor' do
|
26
26
|
subject(:association) { described_class.new(name: :foo) }
|
27
27
|
|
28
28
|
its(:name) { should be :foo }
|
29
|
-
its(:
|
29
|
+
its(:item_mapper) { should be Yaks::Undefined }
|
30
30
|
its(:rel) { should be Yaks::Undefined }
|
31
31
|
its(:href) { should be Yaks::Undefined }
|
32
32
|
its(:link_if) { should be Yaks::Undefined }
|
@@ -132,4 +132,28 @@ RSpec.describe Yaks::Mapper::Association do
|
|
132
132
|
end
|
133
133
|
end
|
134
134
|
end
|
135
|
+
|
136
|
+
describe '.create' do
|
137
|
+
it 'should take a name' do
|
138
|
+
expect(described_class.create(:foo).name).to be :foo
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should optionally take a mapper' do
|
142
|
+
expect(described_class.create(:foo, mapper: :bar).item_mapper).to be :bar
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should take other options' do
|
146
|
+
expect(described_class.create(:foo, mapper: :bar, href: 'xxx').href).to eql 'xxx'
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'should respect attribute defaults' do
|
150
|
+
expect(described_class.create(:foo, href: 'xxx').item_mapper).to be Yaks::Undefined
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'should not munge the options hash' do
|
154
|
+
opts = {mapper: :foo}
|
155
|
+
described_class.create(:foo, opts)
|
156
|
+
expect(opts).to eql(mapper: :foo)
|
157
|
+
end
|
158
|
+
end
|
135
159
|
end
|