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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +46 -0
  3. data/lib/yaks/attributes.rb +45 -0
  4. data/lib/yaks/collection_resource.rb +1 -45
  5. data/lib/yaks/config/dsl.rb +15 -6
  6. data/lib/yaks/config.rb +1 -1
  7. data/lib/yaks/configurable.rb +20 -0
  8. data/lib/yaks/default_policy.rb +0 -8
  9. data/lib/yaks/errors.rb +3 -0
  10. data/lib/yaks/format/hal.rb +13 -2
  11. data/lib/yaks/format/halo.rb +29 -0
  12. data/lib/yaks/mapper/association.rb +18 -13
  13. data/lib/yaks/mapper/association_mapper.rb +1 -1
  14. data/lib/yaks/mapper/attribute.rb +1 -3
  15. data/lib/yaks/mapper/class_methods.rb +24 -16
  16. data/lib/yaks/mapper/config.rb +13 -28
  17. data/lib/yaks/mapper/control.rb +38 -0
  18. data/lib/yaks/mapper/has_many.rb +4 -8
  19. data/lib/yaks/mapper/link.rb +10 -2
  20. data/lib/yaks/mapper.rb +11 -2
  21. data/lib/yaks/resource/control.rb +11 -0
  22. data/lib/yaks/resource/link.rb +1 -7
  23. data/lib/yaks/resource.rb +9 -13
  24. data/lib/yaks/runner.rb +2 -4
  25. data/lib/yaks/serializer.rb +12 -0
  26. data/lib/yaks/stateful_builder.rb +54 -0
  27. data/lib/yaks/version.rb +1 -1
  28. data/lib/yaks.rb +16 -7
  29. data/spec/acceptance/acceptance_spec.rb +14 -4
  30. data/spec/acceptance/models.rb +9 -0
  31. data/spec/integration/map_to_resource_spec.rb +1 -1
  32. data/spec/json/confucius.halo.json +80 -0
  33. data/spec/spec_helper.rb +5 -0
  34. data/spec/support/shared_contexts.rb +1 -1
  35. data/spec/unit/yaks/attributes_spec.rb +65 -0
  36. data/spec/unit/yaks/collection_mapper_spec.rb +1 -1
  37. data/spec/unit/yaks/collection_resource_spec.rb +7 -25
  38. data/spec/unit/yaks/config/dsl_spec.rb +5 -0
  39. data/spec/unit/yaks/config_spec.rb +2 -1
  40. data/spec/unit/yaks/configurable_spec.rb +25 -0
  41. data/spec/unit/yaks/default_policy_spec.rb +1 -7
  42. data/spec/unit/yaks/format/collection_json_spec.rb +1 -1
  43. data/spec/unit/yaks/format/hal_spec.rb +2 -2
  44. data/spec/unit/yaks/format/html_spec.rb +5 -0
  45. data/spec/unit/yaks/format/json_api_spec.rb +1 -1
  46. data/spec/unit/yaks/format_spec.rb +1 -5
  47. data/spec/unit/yaks/mapper/association_mapper_spec.rb +2 -2
  48. data/spec/unit/yaks/mapper/association_spec.rb +27 -3
  49. data/spec/unit/yaks/mapper/class_methods_spec.rb +17 -1
  50. data/spec/unit/yaks/mapper/config_spec.rb +16 -8
  51. data/spec/unit/yaks/mapper/has_many_spec.rb +15 -2
  52. data/spec/unit/yaks/mapper/has_one_spec.rb +1 -1
  53. data/spec/unit/yaks/mapper/link_spec.rb +12 -2
  54. data/spec/unit/yaks/mapper_spec.rb +51 -22
  55. data/spec/unit/yaks/resource/link_spec.rb +2 -1
  56. data/spec/unit/yaks/resource_spec.rb +16 -9
  57. data/spec/unit/yaks/runner_spec.rb +22 -2
  58. data/spec/unit/yaks/serializer_spec.rb +20 -0
  59. data/spec/unit/yaks/stateful_builder_spec.rb +41 -0
  60. data/yaks.gemspec +1 -0
  61. metadata +39 -11
  62. data/lib/yaks/fp/hash_updatable.rb +0 -19
  63. data/lib/yaks/fp/updatable.rb +0 -17
  64. data/spec/unit/yaks/fp/hash_updatable_spec.rb +0 -22
  65. data/spec/unit/yaks/fp/updatable_spec.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1363b84d5c4a3fc9a834c05015bd3b1f0a00450b
4
- data.tar.gz: 90f37a7f613072a718e95023fe5475481096b724
3
+ metadata.gz: 79d98824107ec7c700f39b7776dd1ce517f3283b
4
+ data.tar.gz: 10a45b5d3b2a73054232b63b4b2d70b5dd83c87e
5
5
  SHA512:
6
- metadata.gz: 81db95d4be9d95499da0205e39085611521fdff084abff9902e2cceb8c9677ef24294d912bc537b4874e52008a9694f76f13478af5fcd959931a153a1f171480
7
- data.tar.gz: 73897cc179e778e280ce92197df35084a78e737dee498b9579e6132c8fbdbcff2725dea25ae5394747df8866f2372677c18562c0e21c98f628d32fb72aca33b1
6
+ metadata.gz: 8766e6b07b209e32f739caaa1e965d88a1615501705f9b8e6f6d857d8d4149816aa34ab846b0e37f9605a2ee5fc5359faed766e92f6550efda42bc5d9b4f3ebb
7
+ data.tar.gz: a65eb2384e11a8d9379f558afbaadffc67fc72cfa71fdd19812c905de84884d2a91f57366475a4da636ba987052a58c6f6e4986d9feda24226b153ed108fc22a
data/Rakefile CHANGED
@@ -1,3 +1,49 @@
1
1
  load '../rakelib/shared.rake'
2
2
 
3
3
  gem_tasks(:yaks)
4
+
5
+
6
+ task :mutant_chunked do
7
+ [
8
+ Yaks::Attributes,
9
+ Yaks::Attributes::InstanceMethods,
10
+ Yaks::CollectionMapper,
11
+ Yaks::CollectionResource,
12
+ Yaks::Config,
13
+ Yaks::Config::DSL,
14
+ Yaks::Configurable,
15
+ Yaks::Configurable::ClassMethods,
16
+ Yaks::StatefulBuilder,
17
+ Yaks::DefaultPolicy,
18
+ Yaks::FP,
19
+ Yaks::FP::Callable,
20
+ Yaks::Format,
21
+ Yaks::Format::CollectionJson,
22
+ Yaks::Format::Hal,
23
+ Yaks::Format::Halo,
24
+ Yaks::Format::JsonAPI,
25
+ Yaks::Mapper::AssociationMapper,
26
+ Yaks::Mapper::Attribute,
27
+ Yaks::Mapper::Config,
28
+ Yaks::Mapper::Control,
29
+ Yaks::Mapper::Control::Field,
30
+ Yaks::Mapper::HasOne,
31
+ Yaks::NullResource,
32
+ Yaks::Primitivize,
33
+ Yaks::Resource::Link,
34
+ Yaks::Util,
35
+ Yaks::Serializer,
36
+ Yaks::Runner,
37
+ Yaks::Resource,
38
+ Yaks::Mapper::Link,
39
+ Yaks::Mapper::HasMany,
40
+ Yaks::Mapper::ClassMethods,
41
+ Yaks::Mapper::Association,
42
+ Yaks::Mapper,
43
+ # Yaks::Format::HTML,
44
+ ].each do |space|
45
+ puts space
46
+ ENV['PATTERN'] = "#{space}"
47
+ Rake::Task["mutant"].execute
48
+ end
49
+ end
@@ -0,0 +1,45 @@
1
+ module Yaks
2
+ class Attributes < Module
3
+ attr_reader :defaults, :attributes
4
+
5
+ def initialize(*attrs)
6
+ @defaults = attrs.last.instance_of?(Hash) ? attrs.pop : {}
7
+ @attributes = attrs + @defaults.keys
8
+ end
9
+
10
+ def add(*attrs)
11
+ defaults = attrs.last.instance_of?(Hash) ? attrs.pop : {}
12
+ self.class.new(*[*(attributes+attrs), @defaults.merge(defaults)])
13
+ end
14
+
15
+ def included(descendant)
16
+ descendant.module_exec(self) do |this|
17
+ include InstanceMethods,
18
+ Anima.new(*this.attributes),
19
+ Anima::Update
20
+
21
+ this.attributes.each do |attr|
22
+ define_method attr do |value = Undefined|
23
+ if value.equal? Undefined
24
+ instance_variable_get("@#{attr}")
25
+ else
26
+ update(attr => value)
27
+ end
28
+ end
29
+ end
30
+
31
+ define_singleton_method(:attributes) { this }
32
+ end
33
+ end
34
+
35
+ module InstanceMethods
36
+ def initialize(attributes = {})
37
+ super(self.class.attributes.defaults.merge(attributes))
38
+ end
39
+
40
+ def append_to(type, *objects)
41
+ update(type => instance_variable_get("@#{type}") + objects)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -15,55 +15,11 @@ module Yaks
15
15
  # In the second case a collection has a single "subresource", being its
16
16
  # members.
17
17
  class CollectionResource < Resource
18
- include Equalizer.new(:type, :links, :attributes, :members, :collection_rel)
19
- include FP::HashUpdatable.new(:type, :links, :attributes, :members, :collection_rel)
20
- include Enumerable
18
+ include attributes.add(members: [], collection_rel: 'members')
21
19
 
22
20
  extend Forwardable
23
-
24
- # @!attribute [r] type
25
- # @return [String]
26
- # @!attribute [r] links
27
- # @return [Array]
28
- # @!attribute [r] members
29
- # @return [Array]
30
- # @!attribute [r] collection_rel
31
- # @return [String]
32
- attr_reader :type, :links, :members, :collection_rel
33
-
34
21
  def_delegators :members, :each
35
22
 
36
- # @param [Hash] options
37
- # @return [CollectionResource]
38
- def initialize(options)
39
- super
40
- @members = options.fetch(:members, [])
41
- @collection_rel = options.fetch(:collection_rel, 'members')
42
- end
43
-
44
- # Make a CollectionResource quack like a resource.
45
- #
46
- # At the moment this is only for HAL, which always assumes
47
- # a singular resource at the top level, this way it can treat
48
- # whatever it gets as a single resource with links and subresources,
49
- # we just push the collection down one level.
50
- #
51
- # Once inside subresources the HAL format does check if a resource
52
- # is a collection, since there it does make a distinction, and because
53
- # in that case it will iterate with each/map rather than calling subresources,
54
- # this doesn't cause infinite recursion. Not very pretty, needs looking at.
55
- #
56
- # :(
57
- #
58
- # @return [Hash]
59
- def subresources
60
- if any?
61
- { collection_rel => self }
62
- else
63
- {}
64
- end
65
- end
66
-
67
23
  # @return [Boolean]
68
24
  def collection?
69
25
  true
@@ -50,21 +50,30 @@ module Yaks
50
50
  config.default_format = format
51
51
  end
52
52
 
53
- # Configure JSON serializer
53
+ # Configure serializer for specific output format, e.g. JSON
54
54
  #
55
- # Defaults to JSON.pretty_generate
55
+ # This will override the default registered serializer. Note
56
+ # that extension gems can register their own serializers, see
57
+ # Yaks::Serializer.register
56
58
  #
57
59
  # @example
58
60
  #
59
61
  # yaks = Yaks.new do
60
- # json_serializer &Oj.method(:dump)
62
+ # serializer :json, &Oj.method(:dump)
61
63
  # end
62
64
  #
63
- # @param [Proc] block
65
+ # @type [Symbol] type
66
+ # Output format
67
+ # @param [Proc] serializer
64
68
  # Serialization procedure
65
69
  #
66
- def json_serializer(&block)
67
- config.serializers[:json] = block
70
+ def serializer(type, &serializer)
71
+ config.serializers[type] = serializer
72
+ end
73
+
74
+ # @deprecated
75
+ def json_serializer(&serializer)
76
+ serializer(:json, &serializer)
68
77
  end
69
78
 
70
79
  %w[before after around skip].map(&:intern).each do |hook_type|
data/lib/yaks/config.rb CHANGED
@@ -36,7 +36,7 @@ module Yaks
36
36
  @default_format = :hal
37
37
  @policy_options = {}
38
38
  @primitivize = Primitivize.create
39
- @serializers = {}
39
+ @serializers = Serializer.all.dup
40
40
  @hooks = []
41
41
 
42
42
  DSL.new(self, &blk)
@@ -0,0 +1,20 @@
1
+ module Yaks
2
+ module Configurable
3
+ def self.included(descendant)
4
+ descendant.instance_eval do
5
+ extend ClassMethods
6
+ end
7
+ end
8
+
9
+ module ClassMethods
10
+ def config_method(name, options)
11
+ define_method name do |*args, &block|
12
+ append_to(
13
+ options.fetch(:append_to),
14
+ options.fetch(:create).create(*args, &block)
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -88,13 +88,5 @@ module Yaks
88
88
  URITemplate.new(@options[:rel_template]).expand(rel: relname)
89
89
  end
90
90
 
91
- # @param format_class [Class]
92
- # @return [#call] format_class
93
- def serializer_for_format(format_class)
94
- {
95
- json: JSON.method(:pretty_generate),
96
- html: :to_html.to_proc
97
- }.fetch(format_class.serializer)
98
- end
99
91
  end
100
92
  end
@@ -0,0 +1,3 @@
1
+ module Yaks
2
+ IllegalState = Class.new(StandardError)
3
+ end
@@ -33,8 +33,19 @@ module Yaks
33
33
  # resource.
34
34
  #
35
35
  result = resource.attributes
36
- result = result.merge(:_links => serialize_links(resource.links)) unless resource.links.empty?
37
- result = result.merge(:_embedded => serialize_embedded(resource.subresources)) unless resource.subresources.empty?
36
+
37
+ if resource.links.any?
38
+ result = result.merge(_links: serialize_links(resource.links))
39
+ end
40
+
41
+ if resource.collection?
42
+ result = result.merge(_embedded:
43
+ serialize_embedded(resource.collection_rel => resource))
44
+ elsif resource.subresources.any?
45
+ result = result.merge(_embedded:
46
+ serialize_embedded(resource.subresources))
47
+ end
48
+
38
49
  result
39
50
  end
40
51
 
@@ -0,0 +1,29 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Yaks
4
+ class Format
5
+ # Extension of Hal loosely based on the example by Mike Kelly given at
6
+ # https://gist.github.com/mikekelly/893552
7
+ class Halo < Hal
8
+ register :halo, :json, 'application/halo+json'
9
+
10
+ def serialize_resource(resource)
11
+ if resource.controls.any?
12
+ super.merge(_controls: serialize_controls(resource.controls))
13
+ else
14
+ super
15
+ end
16
+ end
17
+
18
+ def serialize_controls(controls)
19
+ controls.each_with_object({}) do |control, result|
20
+ result[control.name] = serialize_control(control)
21
+ end
22
+ end
23
+
24
+ def serialize_control(control)
25
+ control.to_h.merge(fields: control.fields.map(&:to_h))
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,18 +1,23 @@
1
1
  module Yaks
2
2
  class Mapper
3
3
  class Association
4
- include Equalizer.new(:name, :child_mapper, :rel, :href, :link_if)
5
- include Util
6
-
7
- attr_reader :name, :child_mapper, :rel, :href, :link_if
8
-
9
- def initialize(options)
10
- @name = options.fetch(:name)
11
- @child_mapper = options.fetch(:mapper, Undefined)
12
- @rel = options.fetch(:rel, Undefined)
13
-
14
- @href = options.fetch(:href, Undefined)
15
- @link_if = options.fetch(:link_if, Undefined)
4
+ include Attributes.new(
5
+ name: Undefined,
6
+ item_mapper: Undefined,
7
+ rel: Undefined,
8
+ href: Undefined,
9
+ link_if: Undefined
10
+ ),
11
+ Util
12
+
13
+ def self.create(name, options = {})
14
+ if options.key?(:mapper)
15
+ options = options.dup
16
+ mapper = options.delete(:mapper)
17
+ options[:item_mapper] = mapper
18
+ end
19
+ options[:name] = name
20
+ new(options)
16
21
  end
17
22
 
18
23
  def add_to_resource(resource, parent_mapper, context)
@@ -34,7 +39,7 @@ module Yaks
34
39
 
35
40
  # support for HasOne and HasMany
36
41
  def resolve_association_mapper(policy)
37
- return child_mapper unless child_mapper.equal?(Undefined)
42
+ return item_mapper unless item_mapper.equal?(Undefined)
38
43
  policy.derive_mapper_from_association(self)
39
44
  end
40
45
 
@@ -25,7 +25,7 @@ module Yaks
25
25
  end
26
26
 
27
27
  def add_link(resource)
28
- Link.new(rel, association.href, {})
28
+ Link.create(rel, association.href)
29
29
  .add_to_resource(resource, parent_mapper, nil)
30
30
  # Yaks::Mapper::Link doesn't do anything with the context, making it
31
31
  # hard to test that we pass it a context. Passing nil for now, until
@@ -1,9 +1,7 @@
1
1
  module Yaks
2
2
  class Mapper
3
3
  class Attribute
4
- include Equalizer.new(:name)
5
-
6
- attr_reader :name
4
+ include Concord::Public.new(:name)
7
5
 
8
6
  def initialize(name)
9
7
  @name = name
@@ -3,9 +3,22 @@
3
3
  module Yaks
4
4
  class Mapper
5
5
  module ClassMethods
6
- include Forwardable
7
- include Util
8
- include FP
6
+ include Forwardable,
7
+ Util,
8
+ FP
9
+
10
+ def config(value = Undefined)
11
+ if value.equal? Undefined
12
+ @config
13
+ else
14
+ raise if value.nil?
15
+ @config = value
16
+ end
17
+ end
18
+
19
+ def inherited(child)
20
+ child.config(config)
21
+ end
9
22
 
10
23
  CONFIG_METHODS = [
11
24
  :type,
@@ -13,22 +26,17 @@ module Yaks
13
26
  :link,
14
27
  :profile,
15
28
  :has_one,
16
- :has_many
29
+ :has_many,
30
+ :control
17
31
  ]
18
32
 
19
- def config
20
- @config ||= Config.new nil, [], [], []
21
- @config = yield(@config) if block_given?
22
- @config
23
- end
24
-
25
- def inherited(child)
26
- child.config { @config }
27
- end
28
-
29
33
  CONFIG_METHODS.each do |method_name|
30
- define_method method_name do |*args|
31
- config &send_with_args(method_name, *args)
34
+ define_method method_name do |*args, &block|
35
+ if args.empty?
36
+ config.public_send(method_name, *args, &block)
37
+ else
38
+ config(config.public_send(method_name, *args, &block))
39
+ end
32
40
  end
33
41
  end
34
42
 
@@ -1,17 +1,10 @@
1
1
  module Yaks
2
2
  class Mapper
3
3
  class Config
4
- include Equalizer.new(:type, :attributes, :links, :associations)
5
- include FP::Updatable.new(:type, :attributes, :links, :associations)
6
-
7
- attr_reader :links, :associations
8
-
9
- def initialize(type, attributes, links, associations)
10
- @type = type
11
- @attributes = attributes
12
- @links = links
13
- @associations = associations
14
- end
4
+ include Attributes.new(
5
+ type: nil, attributes: [], links: [], associations: [], controls: []
6
+ ),
7
+ Configurable
15
8
 
16
9
  def type(type = Undefined)
17
10
  return @type if type.equal?(Undefined)
@@ -20,25 +13,17 @@ module Yaks
20
13
 
21
14
  def attributes(*attrs)
22
15
  return @attributes if attrs.empty?
23
- update(attributes: @attributes + attrs.map(&Attribute.method(:new)))
24
- end
25
-
26
- def link(rel, template, options = {})
27
- update(links: @links + [Link.new(rel, template, options)])
28
- end
29
-
30
- def add_association(type, name, options)
31
- update(associations: @associations + [type.new(options.merge(name: name))])
32
- end
33
-
34
- def has_one(name, options = {})
35
- add_association(HasOne, name, options)
36
- end
37
-
38
- def has_many(name, options = {})
39
- add_association(HasMany, name, options)
16
+ append_to(:attributes, *attrs.map(&Attribute.method(:new)))
40
17
  end
41
18
 
19
+ config_method :link, create: Link, append_to: :links
20
+ config_method :has_one, create: HasOne, append_to: :associations
21
+ config_method :has_many, create: HasMany, append_to: :associations
22
+ config_method :attribute, create: Attribute, append_to: :attributes
23
+ config_method :attribute, create: Attribute, append_to: :attributes
24
+ config_method :control,
25
+ create: StatefulBuilder.new(Control, Control.anima.attribute_names + [:field]),
26
+ append_to: :controls
42
27
  end
43
28
  end
44
29
  end
@@ -0,0 +1,38 @@
1
+ module Yaks
2
+ class Mapper
3
+ class Control
4
+ include Attributes.new(
5
+ name: nil, href: nil, title: nil, method: nil, media_type: nil, fields: []
6
+ ),
7
+ Configurable
8
+
9
+ def self.create(name = nil, options = {})
10
+ new({name: name}.merge(options))
11
+ end
12
+
13
+ def add_to_resource(resource, _parent_mapper, _context)
14
+ resource.add_control(
15
+ ::Yaks::Resource::Control.new(to_h.merge(fields: fields.map(&:to_resource_control_field)))
16
+ )
17
+ end
18
+
19
+ class Field
20
+ include Attributes.new(:name, label: nil, type: "text", value: nil)
21
+
22
+ def self.create(*args)
23
+ attrs = args.last.is_a?(Hash) ? args.pop : {}
24
+ if name = args.shift
25
+ attrs = attrs.merge(name: name)
26
+ end
27
+ new(attrs)
28
+ end
29
+
30
+ def to_resource_control_field
31
+ Yaks::Resource::Control::Field.new(to_h)
32
+ end
33
+ end
34
+
35
+ config_method :field, create: Field, append_to: :fields
36
+ end
37
+ end
38
+ end
@@ -1,12 +1,8 @@
1
1
  module Yaks
2
2
  class Mapper
3
3
  class HasMany < Association
4
- include Util
5
-
6
- def initialize(options)
7
- super
8
- @collection_mapper = options.fetch(:collection_mapper, Undefined)
9
- end
4
+ include Util,
5
+ attributes.add(collection_mapper: Undefined)
10
6
 
11
7
  def map_resource(collection, context)
12
8
  return NullResource.new(collection: true) if collection.nil?
@@ -16,9 +12,9 @@ module Yaks
16
12
  collection_mapper(collection, policy).new(context).call(collection)
17
13
  end
18
14
 
19
- def collection_mapper(collection, policy)
15
+ def collection_mapper(collection = nil, policy = nil)
20
16
  return @collection_mapper unless @collection_mapper.equal? Undefined
21
- policy.derive_mapper_from_object(collection)
17
+ policy.derive_mapper_from_object(collection) if policy && collection
22
18
  end
23
19
 
24
20
  def singular_name
@@ -25,11 +25,15 @@ module Yaks
25
25
  # it will receive the mapper instance as argument. Otherwise it is evaluated in the mapper context
26
26
  class Link
27
27
  extend Forwardable
28
- include Concord.new(:rel, :template, :options)
28
+ include Attributes.new(:rel, :template, options: {})
29
29
  include Util
30
30
 
31
31
  def_delegators :uri_template, :expand_partial
32
32
 
33
+ def self.create(rel, template, options = {})
34
+ new(rel: rel, template: template, options: options)
35
+ end
36
+
33
37
  def add_to_resource(resource, mapper, _context)
34
38
  resource_link = map_to_resource_link(mapper)
35
39
  return resource unless resource_link
@@ -70,7 +74,11 @@ module Yaks
70
74
  uri = expand_with(mapper.method(:load_attribute))
71
75
  return if uri.nil?
72
76
 
73
- Resource::Link.new(rel, uri, resource_link_options(mapper))
77
+ Resource::Link.new(
78
+ rel: rel,
79
+ uri: uri,
80
+ options: resource_link_options(mapper)
81
+ )
74
82
  end
75
83
 
76
84
  def expand_with(lookup)
data/lib/yaks/mapper.rb CHANGED
@@ -6,7 +6,9 @@ module Yaks
6
6
  include Util, FP
7
7
 
8
8
  def_delegators 'self.class', :config
9
- def_delegators :config, :attributes, :links, :associations
9
+ def_delegators :config, :attributes, :links, :associations, :controls
10
+
11
+ config Config.new
10
12
 
11
13
  attr_reader :object, :context
12
14
 
@@ -41,7 +43,8 @@ module Yaks
41
43
 
42
44
  [ :map_attributes,
43
45
  :map_links,
44
- :map_subresources
46
+ :map_subresources,
47
+ :map_controls
45
48
  ].inject(Resource.new(type: mapper_name)) do |resource, method|
46
49
  send(method, resource)
47
50
  end
@@ -71,5 +74,11 @@ module Yaks
71
74
  association.add_to_resource(res, self, context)
72
75
  end
73
76
  end
77
+
78
+ def map_controls(resource)
79
+ controls.inject(resource) do |res, control|
80
+ control.add_to_resource(res, self, context)
81
+ end
82
+ end
74
83
  end
75
84
  end
@@ -0,0 +1,11 @@
1
+ module Yaks
2
+ class Resource
3
+ class Control
4
+ include Yaks::Mapper::Control.attributes
5
+
6
+ class Field
7
+ include Yaks::Mapper::Control::Field.attributes
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,13 +1,7 @@
1
1
  module Yaks
2
2
  class Resource
3
3
  class Link
4
- include Equalizer.new(:rel, :uri, :options)
5
-
6
- attr_reader :rel, :uri, :options
7
-
8
- def initialize(rel, uri, options)
9
- @rel, @uri, @options = rel, uri, options
10
- end
4
+ include Attributes.new(:rel, :uri, options: {})
11
5
 
12
6
  def title
13
7
  options[:title]
data/lib/yaks/resource.rb CHANGED
@@ -1,17 +1,9 @@
1
1
  module Yaks
2
2
  class Resource
3
- include Equalizer.new(:type, :links, :attributes, :subresources)
4
- include FP::HashUpdatable.new(:type, :links, :attributes, :subresources)
5
- include Enumerable
6
-
7
- attr_reader :type, :attributes, :links, :subresources
8
-
9
- def initialize(options = {})
10
- @type = options.fetch(:type, nil)
11
- @attributes = options.fetch(:attributes, {})
12
- @links = options.fetch(:links, [])
13
- @subresources = options.fetch(:subresources, {})
14
- end
3
+ include Attributes.new(
4
+ type: nil, links: [], attributes: {}, subresources: {}, controls: []
5
+ ),
6
+ Enumerable
15
7
 
16
8
  def [](attr)
17
9
  attributes[attr]
@@ -41,7 +33,11 @@ module Yaks
41
33
  end
42
34
 
43
35
  def add_link(link)
44
- update(links: @links + [link])
36
+ append_to(:links, link)
37
+ end
38
+
39
+ def add_control(control)
40
+ append_to(:controls, control)
45
41
  end
46
42
 
47
43
  def add_subresource(rel, subresource)