yaks 0.7.7 → 0.8.0.alpha
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 +1 -0
- data/Rakefile +1 -1
- data/lib/yaks/attributes.rb +17 -11
- data/lib/yaks/builder.rb +43 -0
- data/lib/yaks/changelog.rb +2 -2
- data/lib/yaks/collection_mapper.rb +0 -2
- data/lib/yaks/config.rb +52 -32
- data/lib/yaks/configurable.rb +43 -14
- data/lib/yaks/errors.rb +1 -0
- data/lib/yaks/format/collection_json.rb +37 -5
- data/lib/yaks/format/hal.rb +8 -2
- data/lib/yaks/format/halo.rb +16 -9
- data/lib/yaks/format/json_api.rb +21 -2
- data/lib/yaks/format.rb +21 -15
- data/lib/yaks/html5_forms.rb +3 -2
- data/lib/yaks/identifier/link_relation.rb +17 -0
- data/lib/yaks/mapper/attribute.rb +2 -2
- data/lib/yaks/mapper/config.rb +1 -15
- data/lib/yaks/mapper/form/config.rb +21 -0
- data/lib/yaks/mapper/form/field/option.rb +20 -0
- data/lib/yaks/mapper/form/field.rb +13 -26
- data/lib/yaks/mapper/form/fieldset.rb +43 -0
- data/lib/yaks/mapper/form.rb +41 -16
- data/lib/yaks/mapper/link.rb +9 -7
- data/lib/yaks/mapper.rb +15 -7
- data/lib/yaks/null_resource.rb +2 -1
- data/lib/yaks/pipeline.rb +42 -0
- data/lib/yaks/primitivize.rb +0 -1
- data/lib/yaks/reader/hal.rb +63 -0
- data/lib/yaks/resource/form/field.rb +19 -0
- data/lib/yaks/resource/form/fieldset.rb +13 -0
- data/lib/yaks/resource/form.rb +6 -10
- data/lib/yaks/resource.rb +19 -2
- data/lib/yaks/runner.rb +13 -38
- data/lib/yaks/serializer.rb +34 -1
- data/lib/yaks/util.rb +8 -2
- data/lib/yaks/version.rb +1 -1
- data/lib/yaks.rb +37 -10
- data/resources/iana-link-relations.csv +152 -0
- data/spec/acceptance/acceptance_spec.rb +4 -3
- data/spec/acceptance/json_shared_examples.rb +11 -0
- data/spec/acceptance/models.rb +1 -1
- data/spec/integration/dynamic_form_fields_spec.rb +36 -0
- data/spec/integration/fieldset_spec.rb +62 -0
- data/spec/integration/map_to_resource_spec.rb +0 -2
- data/spec/json/confucius.halo.json +0 -1
- data/spec/sanity_spec.rb +0 -2
- data/spec/spec_helper.rb +3 -3
- data/spec/unit/yaks/attributes_spec.rb +3 -5
- data/spec/unit/yaks/{stateful_builder_spec.rb → builder_spec.rb} +8 -10
- data/spec/unit/yaks/collection_mapper_spec.rb +0 -2
- data/spec/unit/yaks/collection_resource_spec.rb +0 -2
- data/spec/unit/yaks/config_spec.rb +9 -15
- data/spec/unit/yaks/default_policy/derive_mapper_from_object_spec.rb +0 -2
- data/spec/unit/yaks/default_policy_spec.rb +0 -2
- data/spec/unit/yaks/format/collection_json_spec.rb +195 -3
- data/spec/unit/yaks/format/hal_spec.rb +0 -2
- data/spec/unit/yaks/format/halo_spec.rb +0 -1
- data/spec/unit/yaks/format/html_spec.rb +0 -2
- data/spec/unit/yaks/format/json_api_spec.rb +0 -2
- data/spec/unit/yaks/format_spec.rb +4 -6
- data/spec/unit/yaks/fp/callable_spec.rb +0 -2
- data/spec/unit/yaks/fp_spec.rb +0 -2
- data/spec/unit/yaks/mapper/association_mapper_spec.rb +0 -2
- data/spec/unit/yaks/mapper/association_spec.rb +0 -2
- data/spec/unit/yaks/mapper/attribute_spec.rb +0 -2
- data/spec/unit/yaks/mapper/config_spec.rb +6 -167
- data/spec/unit/yaks/mapper/form/field_spec.rb +0 -2
- data/spec/unit/yaks/mapper/form_spec.rb +2 -26
- data/spec/unit/yaks/mapper/has_many_spec.rb +0 -2
- data/spec/unit/yaks/mapper/has_one_spec.rb +0 -2
- data/spec/unit/yaks/mapper/link_spec.rb +13 -2
- data/spec/unit/yaks/mapper_spec.rb +2 -10
- data/spec/unit/yaks/null_resource_spec.rb +2 -4
- data/spec/unit/yaks/pipeline_spec.rb +140 -0
- data/spec/unit/yaks/primitivize_spec.rb +0 -2
- data/spec/unit/yaks/resource/link_spec.rb +0 -2
- data/spec/unit/yaks/resource_spec.rb +2 -4
- data/spec/unit/yaks/runner_spec.rb +52 -92
- data/spec/unit/yaks/serializer_spec.rb +0 -2
- data/spec/unit/yaks/util_spec.rb +12 -2
- metadata +58 -23
- data/lib/yaks/config/dsl.rb +0 -174
- data/lib/yaks/mapper/class_methods.rb +0 -47
- data/lib/yaks/stateful_builder.rb +0 -63
- data/spec/unit/yaks/config/dsl_spec.rb +0 -92
- data/spec/unit/yaks/configurable_spec.rb +0 -55
- data/spec/unit/yaks/mapper/class_methods_spec.rb +0 -83
@@ -0,0 +1,20 @@
|
|
1
|
+
module Yaks
|
2
|
+
class Mapper
|
3
|
+
class Form
|
4
|
+
class Field
|
5
|
+
# <option>, as used in a <select>
|
6
|
+
class Option
|
7
|
+
include Attributes.new(:value, :label, selected: false)
|
8
|
+
|
9
|
+
def self.create(value, opts = {})
|
10
|
+
new(opts.merge(value: value))
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_resource
|
14
|
+
to_h #placeholder
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -2,14 +2,17 @@ module Yaks
|
|
2
2
|
class Mapper
|
3
3
|
class Form
|
4
4
|
class Field
|
5
|
-
extend Configurable
|
6
5
|
include Attributes.new(
|
7
6
|
:name,
|
8
7
|
label: nil,
|
9
|
-
options: []
|
8
|
+
options: [].freeze
|
10
9
|
).add(HTML5Forms::FIELD_OPTIONS)
|
11
10
|
|
12
|
-
Builder =
|
11
|
+
Builder = Builder.new(self) do
|
12
|
+
def_set :name
|
13
|
+
def_set :label
|
14
|
+
def_add :option, create: Option, append_to: :options
|
15
|
+
end
|
13
16
|
|
14
17
|
def self.create(*args)
|
15
18
|
attrs = args.last.instance_of?(Hash) ? args.pop : {}
|
@@ -25,38 +28,22 @@ module Yaks
|
|
25
28
|
Resource::Form::Field.new(
|
26
29
|
resource_attributes.each_with_object({}) do |attr, attrs|
|
27
30
|
attrs[attr] = mapper.expand_value(public_send(attr))
|
28
|
-
end.merge(options:
|
31
|
+
end.merge(options: resource_options)
|
29
32
|
)
|
30
33
|
end
|
31
34
|
|
35
|
+
def resource_options
|
36
|
+
# make sure all empty options arrays are the same instance,
|
37
|
+
# makes for prettier #pp
|
38
|
+
options.empty? ? options : options.map(&:to_resource)
|
39
|
+
end
|
40
|
+
|
32
41
|
# All attributes that can be converted 1-to-1 to
|
33
42
|
# Resource::Form::Field
|
34
43
|
def resource_attributes
|
35
44
|
self.class.attributes.names - [:options]
|
36
45
|
end
|
37
|
-
|
38
|
-
# <option>, as used in a <select>
|
39
|
-
class Option
|
40
|
-
include Attributes.new(:value, :label, selected: false)
|
41
|
-
|
42
|
-
def self.create(value, opts = {})
|
43
|
-
new(opts.merge(value: value))
|
44
|
-
end
|
45
|
-
|
46
|
-
def to_resource
|
47
|
-
to_h #placeholder
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
config_method :option, create: Option, append_to: :options
|
52
46
|
end #Field
|
53
|
-
|
54
|
-
config_method :field, create: Field::Builder, append_to: :fields
|
55
|
-
|
56
|
-
HTML5Forms::INPUT_TYPES.each do |type|
|
57
|
-
config_method type, create: Field::Builder, append_to: :fields, defaults: { type: type }
|
58
|
-
end
|
59
|
-
|
60
47
|
end # Form
|
61
48
|
end # Mapper
|
62
49
|
end # Yaks
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Yaks
|
2
|
+
class Mapper
|
3
|
+
class Form
|
4
|
+
class Fieldset
|
5
|
+
extend Forwardable
|
6
|
+
include Concord.new(:config)
|
7
|
+
|
8
|
+
def_delegators :config, :fields, :dynamic_blocks
|
9
|
+
|
10
|
+
ConfigBuilder = Builder.new(Config) do
|
11
|
+
def_add :field, create: Field::Builder, append_to: :fields
|
12
|
+
def_add :fieldset, create: Fieldset, append_to: :fields
|
13
|
+
HTML5Forms::INPUT_TYPES.each do |type|
|
14
|
+
def_add(type,
|
15
|
+
create: Field::Builder,
|
16
|
+
append_to: :fields,
|
17
|
+
defaults: { type: type }
|
18
|
+
)
|
19
|
+
end
|
20
|
+
def_forward :dynamic
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.create(_opts={}, &block)
|
24
|
+
new(ConfigBuilder.build(Config.new, &block))
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_resource(mapper)
|
28
|
+
config = dynamic_blocks.inject(self.config) do |config, block|
|
29
|
+
ConfigBuilder.build(config, mapper.object, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
resource_fields = resource_fields(config.fields, mapper)
|
33
|
+
|
34
|
+
Resource::Form::Fieldset.new(fields: resource_fields)
|
35
|
+
end
|
36
|
+
|
37
|
+
def resource_fields(fields, mapper)
|
38
|
+
fields.map { |field| field.to_resource(mapper) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/yaks/mapper/form.rb
CHANGED
@@ -1,41 +1,66 @@
|
|
1
1
|
module Yaks
|
2
2
|
class Mapper
|
3
3
|
class Form
|
4
|
-
extend
|
5
|
-
include Attributes.new(
|
6
|
-
name: nil, action: nil, title: nil, method: nil, media_type: nil, fields: []
|
7
|
-
)
|
4
|
+
extend Configurable, Forwardable, Util
|
8
5
|
|
9
|
-
|
6
|
+
ConfigBuilder = Builder.new(Config) do
|
7
|
+
def_set :action, :title, :method, :media_type
|
8
|
+
def_add :field, create: Field::Builder, append_to: :fields
|
9
|
+
def_add :fieldset, create: Fieldset, append_to: :fields
|
10
|
+
HTML5Forms::INPUT_TYPES.each do |type|
|
11
|
+
def_add(type,
|
12
|
+
create: Field::Builder,
|
13
|
+
append_to: :fields,
|
14
|
+
defaults: { type: type }
|
15
|
+
)
|
16
|
+
end
|
17
|
+
def_forward :dynamic
|
18
|
+
end
|
10
19
|
|
11
|
-
|
12
|
-
|
13
|
-
self.attributes.names + HTML5Forms::INPUT_TYPES + [:field]
|
14
|
-
)
|
20
|
+
def_delegators :config, :name, :action, :title, :method,
|
21
|
+
:media_type, :fields, :dynamic_blocks
|
15
22
|
|
16
|
-
def self.create(
|
17
|
-
|
23
|
+
def self.create(*args, &block)
|
24
|
+
args, options = extract_options(args)
|
25
|
+
|
26
|
+
if args.first.is_a? Symbol
|
27
|
+
options[:name] = args.first
|
28
|
+
end
|
29
|
+
|
30
|
+
new(ConfigBuilder.build(Config.new(options), &block))
|
18
31
|
end
|
19
32
|
|
33
|
+
############################################################
|
34
|
+
# instance
|
35
|
+
|
36
|
+
include Concord.new(:config)
|
37
|
+
|
20
38
|
def add_to_resource(resource, mapper, _context)
|
21
39
|
resource.add_form(to_resource(mapper))
|
22
40
|
end
|
23
41
|
|
42
|
+
private
|
43
|
+
|
24
44
|
def to_resource(mapper)
|
45
|
+
config = dynamic_blocks.inject(self.config) do |config, block|
|
46
|
+
ConfigBuilder.build(config, mapper.object, &block)
|
47
|
+
end
|
48
|
+
|
25
49
|
attrs = {
|
26
|
-
fields: resource_fields(mapper),
|
27
|
-
action: mapper.expand_uri(action, true)
|
50
|
+
fields: resource_fields(config.fields, mapper),
|
51
|
+
action: mapper.expand_uri(config.action, true)
|
28
52
|
}
|
53
|
+
|
29
54
|
[:name, :title, :method, :media_type].each do |attr|
|
30
|
-
attrs[attr] = mapper.expand_value(public_send(attr))
|
55
|
+
attrs[attr] = mapper.expand_value(config.public_send(attr))
|
31
56
|
end
|
57
|
+
|
32
58
|
Resource::Form.new(attrs)
|
33
59
|
end
|
34
60
|
|
35
|
-
def resource_fields(mapper)
|
61
|
+
def resource_fields(fields, mapper)
|
36
62
|
fields.map { |field| field.to_resource(mapper) }
|
37
63
|
end
|
38
|
-
|
39
64
|
end
|
40
65
|
end
|
41
66
|
end
|
data/lib/yaks/mapper/link.rb
CHANGED
@@ -24,19 +24,21 @@ module Yaks
|
|
24
24
|
# @option title [#to_proc] Block that returns the title. If it takes an argument,
|
25
25
|
# it will receive the mapper instance as argument. Otherwise it is evaluated in the mapper context
|
26
26
|
class Link
|
27
|
-
extend Forwardable
|
28
|
-
include Attributes.new(:rel, :template, options: {})
|
29
|
-
include Util
|
27
|
+
extend Forwardable, Util
|
28
|
+
include Attributes.new(:rel, :template, options: {}), Util
|
30
29
|
|
31
|
-
def self.create(
|
32
|
-
|
30
|
+
def self.create(*args)
|
31
|
+
args, options = extract_options(args)
|
32
|
+
new(rel: args[0], template: args[1], options: options)
|
33
33
|
end
|
34
34
|
|
35
35
|
def add_to_resource(resource, mapper, _context)
|
36
36
|
resource_link = map_to_resource_link(mapper)
|
37
37
|
return resource unless resource_link
|
38
|
-
if options[:
|
39
|
-
resource.links
|
38
|
+
if options[:remove]
|
39
|
+
resource.with(links: resource.links.reject {|link| link.rel?(rel)})
|
40
|
+
elsif options[:replace]
|
41
|
+
resource.with(links: resource.links.reject {|link| link.rel?(rel)} << resource_link)
|
40
42
|
else
|
41
43
|
resource.add_link(resource_link)
|
42
44
|
end
|
data/lib/yaks/mapper.rb
CHANGED
@@ -1,17 +1,25 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
|
3
1
|
module Yaks
|
4
2
|
class Mapper
|
5
|
-
extend
|
6
|
-
include Util, FP, FP::Callable
|
3
|
+
extend Configurable
|
7
4
|
|
8
|
-
|
9
|
-
|
5
|
+
def_forward :type => :with_type
|
6
|
+
def_forward :attributes => :add_attributes
|
7
|
+
def_forward :append_to
|
10
8
|
|
11
|
-
|
9
|
+
def_add :link, create: Link, append_to: :links
|
10
|
+
def_add :has_one, create: HasOne, append_to: :associations
|
11
|
+
def_add :has_many, create: HasMany, append_to: :associations
|
12
|
+
def_add :attribute, create: Attribute, append_to: :attributes
|
13
|
+
def_add :form, create: Form, append_to: :forms
|
14
|
+
|
15
|
+
extend Forwardable
|
16
|
+
include Util, FP, FP::Callable
|
12
17
|
|
13
18
|
attr_reader :object, :context
|
14
19
|
|
20
|
+
def_delegators 'self.class', :config
|
21
|
+
def_delegators :config, :attributes, :links, :associations, :forms
|
22
|
+
|
15
23
|
def initialize(context)
|
16
24
|
@context = context
|
17
25
|
end
|
data/lib/yaks/null_resource.rb
CHANGED
@@ -18,6 +18,7 @@ module Yaks
|
|
18
18
|
@collection
|
19
19
|
end
|
20
20
|
|
21
|
+
|
21
22
|
def null_resource?
|
22
23
|
true
|
23
24
|
end
|
@@ -31,7 +32,7 @@ module Yaks
|
|
31
32
|
raise UnsupportedOperationError, "Operation #{__method__} not supported on #{self.class}"
|
32
33
|
end
|
33
34
|
|
34
|
-
def
|
35
|
+
def merge_attributes(_new_attrs)
|
35
36
|
raise UnsupportedOperationError, "Operation #{__method__} not supported on #{self.class}"
|
36
37
|
end
|
37
38
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Yaks
|
2
|
+
class Pipeline
|
3
|
+
include Concord.new(:steps)
|
4
|
+
|
5
|
+
def call(input, env)
|
6
|
+
steps.inject(input) {|memo, (_, step)| step.call(memo, env) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def insert_hooks(hooks)
|
10
|
+
new_steps = hooks.inject(steps) do |steps, (type, target_step, name, hook)|
|
11
|
+
steps.flat_map do |step_name, callable|
|
12
|
+
if step_name.equal? target_step
|
13
|
+
case type
|
14
|
+
when :before
|
15
|
+
[[name, hook], [step_name, callable]]
|
16
|
+
when :after
|
17
|
+
[[step_name, callable], [name, hook]]
|
18
|
+
when :around
|
19
|
+
[[name, ->(x, env) { hook.call(x, env, &callable) }]]
|
20
|
+
when :skip
|
21
|
+
[]
|
22
|
+
end
|
23
|
+
end || [[step_name, callable]]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
self.class.new(new_steps)
|
28
|
+
end
|
29
|
+
|
30
|
+
def transitive?
|
31
|
+
steps.all? {|name, step| step.respond_to?(:transitive?) && step.transitive?}
|
32
|
+
end
|
33
|
+
|
34
|
+
def inverse
|
35
|
+
unless transitive?
|
36
|
+
raise RuntimeError, "Unable to get inverse pipeline, not all pipeline steps are transitive."
|
37
|
+
end
|
38
|
+
|
39
|
+
self.class.new(steps.map {|name, step| [name, step.inverse]}.reverse)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/yaks/primitivize.rb
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
module Yaks
|
2
|
+
module Reader
|
3
|
+
class Hal
|
4
|
+
|
5
|
+
def call(parsed_json, env = {})
|
6
|
+
attributes = parsed_json.dup
|
7
|
+
links = convert_links(attributes.delete('_links') || {})
|
8
|
+
embedded = convert_embedded(attributes.delete('_embedded') || {})
|
9
|
+
|
10
|
+
|
11
|
+
Resource.new(
|
12
|
+
type: attributes.delete('type') || type_from_links(links),
|
13
|
+
attributes: Util.symbolize_keys(attributes),
|
14
|
+
links: links,
|
15
|
+
subresources: embedded
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def type_from_links(links)
|
20
|
+
profile = links.detect {|l| l.rel?(:profile)}
|
21
|
+
profile.uri[/\w+$/] if profile
|
22
|
+
end
|
23
|
+
|
24
|
+
def convert_links(links)
|
25
|
+
Set[*
|
26
|
+
links.flat_map do |rel, link|
|
27
|
+
array(link).map do |l|
|
28
|
+
options = Util.symbolize_keys(Util.slice_hash(l, 'title', 'templated'))
|
29
|
+
rel = rel.to_sym if Yaks::Identifier::LinkRelation.iana?(rel)
|
30
|
+
Resource::Link.new(rel: rel, uri: l['href'], options: options)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
def array(x)
|
37
|
+
x.instance_of?(Array) ? x : [x]
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def convert_embedded(embedded)
|
42
|
+
embedded.flat_map do |rel, resource|
|
43
|
+
case resource
|
44
|
+
when nil
|
45
|
+
NullResource.new
|
46
|
+
when Array
|
47
|
+
if resource.empty?
|
48
|
+
NullResource.new(collection: true)
|
49
|
+
else
|
50
|
+
CollectionResource.new(
|
51
|
+
members: resource.map { |r|
|
52
|
+
call(r).with(type: Util.singularize(rel[/\w+$/])) }
|
53
|
+
)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
call(resource)
|
57
|
+
end.with(rels: [rel])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Yaks
|
2
|
+
class Resource
|
3
|
+
class Form
|
4
|
+
class Field
|
5
|
+
include Yaks::Mapper::Form::Field.attributes.add(:error => nil)
|
6
|
+
|
7
|
+
def value(arg = Undefined)
|
8
|
+
return @value if arg.eql?(Undefined)
|
9
|
+
if type == :select
|
10
|
+
selected = options.find { |option| option.selected }
|
11
|
+
selected.value if selected
|
12
|
+
else
|
13
|
+
with(value: arg)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/yaks/resource/form.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Yaks
|
2
2
|
class Resource
|
3
3
|
class Form
|
4
|
-
include Yaks::Mapper::Form.attributes
|
4
|
+
include Yaks::Mapper::Form::Config.attributes.remove(:dynamic_blocks)
|
5
5
|
|
6
6
|
def [](name)
|
7
7
|
fields.find {|field| field.name == name}.value
|
@@ -13,16 +13,12 @@ module Yaks
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
return @value if arg.eql?(Undefined)
|
21
|
-
if type == :select
|
22
|
-
selected = options.find { |option| option.selected }
|
23
|
-
selected.value if selected
|
16
|
+
def fields_flat(fields = fields)
|
17
|
+
fields.each_with_object([]) do |field, acc|
|
18
|
+
if field.type == :fieldset
|
19
|
+
acc.concat(fields_flat field.fields)
|
24
20
|
else
|
25
|
-
|
21
|
+
acc << field
|
26
22
|
end
|
27
23
|
end
|
28
24
|
end
|
data/lib/yaks/resource.rb
CHANGED
@@ -8,6 +8,7 @@ module Yaks
|
|
8
8
|
subresources: [],
|
9
9
|
forms: []
|
10
10
|
)
|
11
|
+
extend Util::Deprecated
|
11
12
|
|
12
13
|
def initialize(attrs = {})
|
13
14
|
raise attrs.inspect if attrs.key?(:subresources) && !attrs[:subresources].instance_of?(Array)
|
@@ -27,6 +28,16 @@ module Yaks
|
|
27
28
|
end
|
28
29
|
|
29
30
|
def self_link
|
31
|
+
# This reverse is there so that the last :self link specified
|
32
|
+
# "wins". The use case is having a self link defined in a base
|
33
|
+
# mapper class, but having it overridden in specific
|
34
|
+
# subclasses. In combination with formats that expect resources
|
35
|
+
# to have up to one self link, this is the preferred behavior.
|
36
|
+
# However since 0.7.5 links take a "replace: true" option to
|
37
|
+
# specifiy they should replace previous defintions with the same
|
38
|
+
# rel, wich should be used instead. The behavior that the last
|
39
|
+
# link "wins" will be deprecated, the result of multiple links
|
40
|
+
# with the same rel will be unspecified.
|
30
41
|
links.reverse.find do |link|
|
31
42
|
link.rel.equal? :self
|
32
43
|
end
|
@@ -37,6 +48,10 @@ module Yaks
|
|
37
48
|
end
|
38
49
|
alias collection collection?
|
39
50
|
|
51
|
+
def with_collection(*)
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
40
55
|
def null_resource?
|
41
56
|
false
|
42
57
|
end
|
@@ -47,10 +62,12 @@ module Yaks
|
|
47
62
|
alias each members
|
48
63
|
alias map members
|
49
64
|
alias each_with_object members
|
65
|
+
alias with_members members
|
50
66
|
|
51
|
-
def
|
52
|
-
|
67
|
+
def merge_attributes(new_attrs)
|
68
|
+
with(attributes: @attributes.merge(new_attrs))
|
53
69
|
end
|
70
|
+
deprecated_alias :update_attributes, :merge_attributes
|
54
71
|
|
55
72
|
def add_rel(rel)
|
56
73
|
append_to(:rels, rel)
|
data/lib/yaks/runner.rb
CHANGED
@@ -5,18 +5,20 @@ module Yaks
|
|
5
5
|
include Adamantium::Flat
|
6
6
|
extend Forwardable
|
7
7
|
|
8
|
-
def_delegators :config,
|
8
|
+
def_delegators :config, :policy, :default_format, :format_options_hash,
|
9
|
+
:primitivize, :serializers
|
10
|
+
def_delegators :format_class, :media_type, :format_name
|
9
11
|
|
10
12
|
def call
|
11
|
-
|
13
|
+
Pipeline.new(steps).insert_hooks(hooks).call(object, env)
|
12
14
|
end
|
13
15
|
|
14
|
-
def
|
15
|
-
|
16
|
+
def read
|
17
|
+
Pipeline.new([[:parse, serializer.inverse], [:format, formatter.inverse]]).insert_hooks(hooks).call(object, env)
|
16
18
|
end
|
17
19
|
|
18
|
-
def
|
19
|
-
|
20
|
+
def map
|
21
|
+
Pipeline.new([[:map, mapper]]).insert_hooks(hooks).call(object, env)
|
20
22
|
end
|
21
23
|
|
22
24
|
def context
|
@@ -41,20 +43,11 @@ module Yaks
|
|
41
43
|
end
|
42
44
|
memoize :format_class
|
43
45
|
|
44
|
-
def media_type
|
45
|
-
format_class.media_type
|
46
|
-
end
|
47
|
-
|
48
|
-
def format_name
|
49
|
-
format_class.format_name
|
50
|
-
end
|
51
|
-
|
52
46
|
def steps
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
[ :serialize, serializer ]])
|
47
|
+
[[ :map, mapper ],
|
48
|
+
[ :format, formatter ],
|
49
|
+
[ :primitivize, primitivizer],
|
50
|
+
[ :serialize, serializer ]]
|
58
51
|
end
|
59
52
|
memoize :steps
|
60
53
|
|
@@ -66,7 +59,7 @@ module Yaks
|
|
66
59
|
memoize :mapper, freezer: :noop
|
67
60
|
|
68
61
|
def formatter
|
69
|
-
format_class.new(
|
62
|
+
format_class.new(format_options_hash[format_name])
|
70
63
|
end
|
71
64
|
memoize :formatter
|
72
65
|
|
@@ -90,23 +83,5 @@ module Yaks
|
|
90
83
|
config.hooks + options.fetch(:hooks, [])
|
91
84
|
end
|
92
85
|
|
93
|
-
def insert_hooks(steps)
|
94
|
-
hooks.inject(steps) do |steps, (type, target_step, name, hook)|
|
95
|
-
steps.flat_map do |step_name, callable|
|
96
|
-
if step_name.equal? target_step
|
97
|
-
case type
|
98
|
-
when :before
|
99
|
-
[[name, hook], [step_name, callable]]
|
100
|
-
when :after
|
101
|
-
[[step_name, callable], [name, hook]]
|
102
|
-
when :around
|
103
|
-
[[step_name, ->(x, env) { hook.call(x, env, &callable) }]]
|
104
|
-
when :skip
|
105
|
-
[]
|
106
|
-
end
|
107
|
-
end || [[step_name, callable]]
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
86
|
end
|
112
87
|
end
|
data/lib/yaks/serializer.rb
CHANGED
@@ -6,7 +6,40 @@ module Yaks
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def self.all
|
9
|
-
@serializers ||= {json:
|
9
|
+
@serializers ||= {json: JSONWriter}
|
10
10
|
end
|
11
|
+
|
12
|
+
module JSONWriter
|
13
|
+
extend Yaks::FP::Callable
|
14
|
+
|
15
|
+
def self.call(data, env)
|
16
|
+
JSON.pretty_generate(data)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.transitive?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.inverse
|
24
|
+
JSONReader
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module JSONReader
|
29
|
+
extend Yaks::FP::Callable
|
30
|
+
|
31
|
+
def self.call(data, env)
|
32
|
+
JSON.parse(data)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.transitive?
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.inverse
|
40
|
+
JSONWriter
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
11
44
|
end
|
12
45
|
end
|
data/lib/yaks/util.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
|
3
1
|
module Yaks
|
4
2
|
module Util
|
5
3
|
extend self
|
@@ -23,6 +21,14 @@ module Yaks
|
|
23
21
|
keys.each_with_object({}) {|k,dest| dest[k] = hash[k] if hash.key?(k) }
|
24
22
|
end
|
25
23
|
|
24
|
+
def symbolize_keys(hash)
|
25
|
+
hash.each_with_object({}) {|(k,v), hsh| hsh[k.to_sym] = v}
|
26
|
+
end
|
27
|
+
|
28
|
+
def extract_options(args)
|
29
|
+
args.last.is_a?(Hash) ? [args[0..-2], args.last] : [args, {}]
|
30
|
+
end
|
31
|
+
|
26
32
|
# Turn what is maybe a Proc into its result (or itself)
|
27
33
|
#
|
28
34
|
# When input can be either a value or a proc that returns a value,
|
data/lib/yaks/version.rb
CHANGED