yaks 0.7.7 → 0.8.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- 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