yaks 0.3.1 → 0.4.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/.gitignore +1 -0
 - data/CHANGELOG.md +11 -0
 - data/Gemfile +0 -2
 - data/LICENSE +7 -0
 - data/README.md +160 -35
 - data/Rakefile +2 -1
 - data/lib/yaks/collection_mapper.rb +25 -18
 - data/lib/yaks/collection_resource.rb +11 -17
 - data/lib/yaks/config.rb +96 -0
 - data/lib/yaks/default_policy.rb +34 -4
 - data/lib/yaks/fp.rb +18 -0
 - data/lib/yaks/mapper/association.rb +19 -27
 - data/lib/yaks/mapper/class_methods.rb +4 -2
 - data/lib/yaks/mapper/config.rb +24 -39
 - data/lib/yaks/mapper/has_many.rb +7 -6
 - data/lib/yaks/mapper/has_one.rb +4 -3
 - data/lib/yaks/mapper/link.rb +52 -55
 - data/lib/yaks/mapper.rb +38 -26
 - data/lib/yaks/null_resource.rb +3 -3
 - data/lib/yaks/primitivize.rb +29 -27
 - data/lib/yaks/resource/link.rb +4 -0
 - data/lib/yaks/resource.rb +18 -7
 - data/lib/yaks/serializer/collection_json.rb +38 -0
 - data/lib/yaks/serializer/hal.rb +55 -0
 - data/lib/yaks/serializer/json_api.rb +61 -0
 - data/lib/yaks/serializer.rb +25 -4
 - data/lib/yaks/util.rb +2 -42
 - data/lib/yaks/version.rb +1 -1
 - data/lib/yaks.rb +10 -32
 - data/notes.org +72 -0
 - data/shaved_yak.gif +0 -0
 - data/spec/acceptance/acceptance_spec.rb +46 -0
 - data/spec/acceptance/models.rb +28 -0
 - data/spec/integration/map_to_resource_spec.rb +11 -15
 - data/spec/json/confucius.hal.json +23 -0
 - data/spec/json/confucius.json_api.json +22 -0
 - data/spec/json/john.hal.json +29 -0
 - data/spec/json/youtypeitwepostit.collection.json +45 -0
 - data/spec/spec_helper.rb +12 -1
 - data/spec/support/shared_contexts.rb +7 -10
 - data/spec/support/youtypeit_models_mappers.rb +20 -0
 - data/spec/unit/yaks/collection_mapper_spec.rb +84 -0
 - data/spec/unit/yaks/collection_resource_spec.rb +72 -0
 - data/spec/unit/yaks/config_spec.rb +129 -0
 - data/spec/unit/yaks/fp_spec.rb +31 -0
 - data/spec/unit/yaks/mapper/association_spec.rb +80 -0
 - data/spec/{yaks → unit/yaks}/mapper/class_methods_spec.rb +4 -4
 - data/spec/unit/yaks/mapper/config_spec.rb +191 -0
 - data/spec/unit/yaks/mapper/has_many_spec.rb +46 -0
 - data/spec/unit/yaks/mapper/has_one_spec.rb +34 -0
 - data/spec/unit/yaks/mapper/link_spec.rb +152 -0
 - data/spec/unit/yaks/mapper_spec.rb +177 -0
 - data/spec/unit/yaks/resource_spec.rb +40 -0
 - data/spec/{yaks/hal_serializer_spec.rb → unit/yaks/serializer/hal_spec.rb} +2 -2
 - data/spec/unit/yaks/serializer_spec.rb +12 -0
 - data/spec/unit/yaks/util_spec.rb +43 -0
 - data/spec/yaml/confucius.yaml +10 -0
 - data/spec/yaml/youtypeitwepostit.yaml +9 -0
 - data/yaks.gemspec +7 -8
 - metadata +92 -53
 - data/Gemfile.lock +0 -111
 - data/lib/yaks/hal_serializer.rb +0 -59
 - data/lib/yaks/json_api_serializer.rb +0 -59
 - data/lib/yaks/link_lookup.rb +0 -23
 - data/lib/yaks/mapper/lookup.rb +0 -19
 - data/lib/yaks/mapper/map_links.rb +0 -17
 - data/lib/yaks/profile_registry.rb +0 -60
 - data/lib/yaks/rel_registry.rb +0 -20
 - data/lib/yaks/shared_options.rb +0 -15
 - data/spec/support/shorthands.rb +0 -22
 - data/spec/yaks/collection_resource_spec.rb +0 -9
 - data/spec/yaks/mapper/association_spec.rb +0 -21
 - data/spec/yaks/mapper/config_spec.rb +0 -77
 - data/spec/yaks/mapper/has_one_spec.rb +0 -16
 - data/spec/yaks/mapper/link_spec.rb +0 -38
 - data/spec/yaks/mapper/map_links_spec.rb +0 -46
 - data/spec/yaks/mapper_spec.rb +0 -65
 - data/spec/yaks/resource_spec.rb +0 -23
 
| 
         @@ -1,48 +1,40 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Yaks
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Mapper
         
     | 
| 
       3 
3 
     | 
    
         
             
                class Association
         
     | 
| 
       4 
     | 
    
         
            -
                  include Equalizer.new(:name, : 
     | 
| 
       5 
     | 
    
         
            -
                  include SharedOptions
         
     | 
| 
      
 4 
     | 
    
         
            +
                  include Equalizer.new(:name, :mapper, :rel)
         
     | 
| 
       6 
5 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
                  attr_reader :name, : 
     | 
| 
       8 
     | 
    
         
            -
                  private :links, :options
         
     | 
| 
      
 6 
     | 
    
         
            +
                  attr_reader :name, :mapper, :rel, :collection_mapper
         
     | 
| 
       9 
7 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                  def initialize(name,  
     | 
| 
       11 
     | 
    
         
            -
                    @name 
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                    @mapper  = mapper
         
     | 
| 
       14 
     | 
    
         
            -
                    @links   = links
         
     | 
| 
       15 
     | 
    
         
            -
                    @options = options
         
     | 
| 
      
 8 
     | 
    
         
            +
                  def initialize(name, mapper, rel, collection_mapper)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @name, @mapper, @rel, @collection_mapper =
         
     | 
| 
      
 10 
     | 
    
         
            +
                      name, mapper, rel, collection_mapper
         
     | 
| 
       16 
11 
     | 
    
         
             
                  end
         
     | 
| 
       17 
12 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
                   
     | 
| 
       19 
     | 
    
         
            -
                    links.detect {|link| link.rel? :self }
         
     | 
| 
       20 
     | 
    
         
            -
                  end
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                  # @param [Symbol] src_type
         
     | 
| 
       23 
     | 
    
         
            -
                  #   The profile type of the resource that contains the association
         
     | 
| 
       24 
     | 
    
         
            -
                  # @param [#call] loader
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # @param [#call] lookup
         
     | 
| 
       25 
14 
     | 
    
         
             
                  #   A callable that can retrieve an association by its name
         
     | 
| 
       26 
     | 
    
         
            -
                  # @param [Hash] options
         
     | 
| 
       27 
15 
     | 
    
         
             
                  # @return Array[rel, resource]
         
     | 
| 
       28 
16 
     | 
    
         
             
                  #   Returns the rel (registered type or URI) + the associated, mapped resource
         
     | 
| 
       29 
     | 
    
         
            -
                  def  
     | 
| 
      
 17 
     | 
    
         
            +
                  def create_subresource(parent_mapper, lookup, context)
         
     | 
| 
       30 
18 
     | 
    
         
             
                    [
         
     | 
| 
       31 
     | 
    
         
            -
                       
     | 
| 
       32 
     | 
    
         
            -
                      map_resource( 
     | 
| 
      
 19 
     | 
    
         
            +
                      map_rel(parent_mapper, context.fetch(:policy)),
         
     | 
| 
      
 20 
     | 
    
         
            +
                      map_resource(lookup[name], context)
         
     | 
| 
       33 
21 
     | 
    
         
             
                    ]
         
     | 
| 
       34 
22 
     | 
    
         
             
                  end
         
     | 
| 
       35 
23 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
                   
     | 
| 
      
 24 
     | 
    
         
            +
                  def map_rel(parent_mapper, policy)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    return @rel unless @rel.equal?(Undefined)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    policy.derive_rel_from_association(parent_mapper, self)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
       37 
28 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
                  def  
     | 
| 
       39 
     | 
    
         
            -
                    return  
     | 
| 
       40 
     | 
    
         
            -
                     
     | 
| 
      
 29 
     | 
    
         
            +
                  def association_mapper(policy)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    return @mapper unless @mapper.equal?(Undefined)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    policy.derive_mapper_from_association(self)
         
     | 
| 
       41 
32 
     | 
    
         
             
                  end
         
     | 
| 
       42 
33 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                   
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
      
 34 
     | 
    
         
            +
                  # @abstract
         
     | 
| 
      
 35 
     | 
    
         
            +
                  def map_resource(object, context)
         
     | 
| 
       45 
36 
     | 
    
         
             
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
       46 
38 
     | 
    
         
             
                end
         
     | 
| 
       47 
39 
     | 
    
         
             
              end
         
     | 
| 
       48 
40 
     | 
    
         
             
            end
         
     | 
| 
         @@ -5,8 +5,10 @@ module Yaks 
     | 
|
| 
       5 
5 
     | 
    
         
             
                module ClassMethods
         
     | 
| 
       6 
6 
     | 
    
         
             
                  include Forwardable
         
     | 
| 
       7 
7 
     | 
    
         
             
                  include Util
         
     | 
| 
      
 8 
     | 
    
         
            +
                  include FP
         
     | 
| 
       8 
9 
     | 
    
         | 
| 
       9 
10 
     | 
    
         
             
                  CONFIG_METHODS = [
         
     | 
| 
      
 11 
     | 
    
         
            +
                    :type,
         
     | 
| 
       10 
12 
     | 
    
         
             
                    :attributes,
         
     | 
| 
       11 
13 
     | 
    
         
             
                    :link,
         
     | 
| 
       12 
14 
     | 
    
         
             
                    :profile,
         
     | 
| 
         @@ -16,7 +18,7 @@ module Yaks 
     | 
|
| 
       16 
18 
     | 
    
         
             
                  ]
         
     | 
| 
       17 
19 
     | 
    
         | 
| 
       18 
20 
     | 
    
         
             
                  def config
         
     | 
| 
       19 
     | 
    
         
            -
                    @config ||= Config.new
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @config ||= Config.new nil, [], [], []
         
     | 
| 
       20 
22 
     | 
    
         
             
                    @config = yield(@config) if block_given?
         
     | 
| 
       21 
23 
     | 
    
         
             
                    @config
         
     | 
| 
       22 
24 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -27,7 +29,7 @@ module Yaks 
     | 
|
| 
       27 
29 
     | 
    
         | 
| 
       28 
30 
     | 
    
         
             
                  CONFIG_METHODS.each do |method_name|
         
     | 
| 
       29 
31 
     | 
    
         
             
                    define_method method_name do |*args|
         
     | 
| 
       30 
     | 
    
         
            -
                      config  
     | 
| 
      
 32 
     | 
    
         
            +
                      config &send_with_args(method_name, *args)
         
     | 
| 
       31 
33 
     | 
    
         
             
                    end
         
     | 
| 
       32 
34 
     | 
    
         
             
                  end
         
     | 
| 
       33 
35 
     | 
    
         | 
    
        data/lib/yaks/mapper/config.rb
    CHANGED
    
    | 
         @@ -1,50 +1,44 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Yaks
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Mapper
         
     | 
| 
       3 
3 
     | 
    
         
             
                class Config
         
     | 
| 
       4 
     | 
    
         
            -
                  include Equalizer.new(:attributes)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  include Equalizer.new(:type, :attributes, :links, :associations)
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
                   
     | 
| 
      
 6 
     | 
    
         
            +
                  attr_reader :links, :associations
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def initialize(type, attributes, links, associations)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @type         = type
         
     | 
| 
       7 
10 
     | 
    
         
             
                    @attributes   = attributes
         
     | 
| 
       8 
11 
     | 
    
         
             
                    @links        = links
         
     | 
| 
       9 
12 
     | 
    
         
             
                    @associations = associations
         
     | 
| 
       10 
     | 
    
         
            -
                    @profile      = profile
         
     | 
| 
       11 
     | 
    
         
            -
                    freeze
         
     | 
| 
       12 
13 
     | 
    
         
             
                  end
         
     | 
| 
       13 
14 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
                  def  
     | 
| 
      
 15 
     | 
    
         
            +
                  def updated(updates)
         
     | 
| 
       15 
16 
     | 
    
         
             
                    self.class.new(
         
     | 
| 
      
 17 
     | 
    
         
            +
                      updates.fetch(:type)         { type         },
         
     | 
| 
       16 
18 
     | 
    
         
             
                      updates.fetch(:attributes)   { attributes   },
         
     | 
| 
       17 
19 
     | 
    
         
             
                      updates.fetch(:links)        { links        },
         
     | 
| 
       18 
     | 
    
         
            -
                      updates.fetch(:associations) { associations } 
     | 
| 
       19 
     | 
    
         
            -
                      updates.fetch(:profile)      { profile      },
         
     | 
| 
      
 20 
     | 
    
         
            +
                      updates.fetch(:associations) { associations }
         
     | 
| 
       20 
21 
     | 
    
         
             
                    )
         
     | 
| 
       21 
22 
     | 
    
         
             
                  end
         
     | 
| 
       22 
23 
     | 
    
         | 
| 
      
 24 
     | 
    
         
            +
                  def type(type = Undefined)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    return @type if type.equal?(Undefined)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    updated(type: type)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
       23 
29 
     | 
    
         
             
                  def attributes(*attrs)
         
     | 
| 
       24 
30 
     | 
    
         
             
                    return @attributes if attrs.empty?
         
     | 
| 
       25 
     | 
    
         
            -
                     
     | 
| 
       26 
     | 
    
         
            -
                      attributes: @attributes + attrs 
     | 
| 
      
 31 
     | 
    
         
            +
                    updated(
         
     | 
| 
      
 32 
     | 
    
         
            +
                      attributes: @attributes + attrs
         
     | 
| 
       27 
33 
     | 
    
         
             
                    )
         
     | 
| 
       28 
34 
     | 
    
         
             
                  end
         
     | 
| 
       29 
35 
     | 
    
         | 
| 
       30 
36 
     | 
    
         
             
                  def link(rel, template, options = {})
         
     | 
| 
       31 
     | 
    
         
            -
                     
     | 
| 
       32 
     | 
    
         
            -
                      links: @links 
     | 
| 
       33 
     | 
    
         
            -
                    )
         
     | 
| 
       34 
     | 
    
         
            -
                  end
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
                  def profile(type = Undefined)
         
     | 
| 
       37 
     | 
    
         
            -
                    return @profile if type == Undefined
         
     | 
| 
       38 
     | 
    
         
            -
                    new(
         
     | 
| 
       39 
     | 
    
         
            -
                      profile: type
         
     | 
| 
      
 37 
     | 
    
         
            +
                    updated(
         
     | 
| 
      
 38 
     | 
    
         
            +
                      links: @links + [Link.new(rel, template, options)]
         
     | 
| 
       40 
39 
     | 
    
         
             
                    )
         
     | 
| 
       41 
40 
     | 
    
         
             
                  end
         
     | 
| 
       42 
41 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                  # key
         
     | 
| 
       44 
     | 
    
         
            -
                  # embed_style
         
     | 
| 
       45 
     | 
    
         
            -
                  # rel
         
     | 
| 
       46 
     | 
    
         
            -
                  # (profile)
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
42 
     | 
    
         
             
                  def has_one(name, options = {})
         
     | 
| 
       49 
43 
     | 
    
         
             
                    add_association(HasOne, name, options)
         
     | 
| 
       50 
44 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -53,27 +47,18 @@ module Yaks 
     | 
|
| 
       53 
47 
     | 
    
         
             
                    add_association(HasMany, name, options)
         
     | 
| 
       54 
48 
     | 
    
         
             
                  end
         
     | 
| 
       55 
49 
     | 
    
         | 
| 
       56 
     | 
    
         
            -
                  def add_association(type, name, options 
     | 
| 
       57 
     | 
    
         
            -
                     
     | 
| 
       58 
     | 
    
         
            -
                      associations: @associations 
     | 
| 
      
 50 
     | 
    
         
            +
                  def add_association(type, name, options)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    updated(
         
     | 
| 
      
 52 
     | 
    
         
            +
                      associations: @associations + [
         
     | 
| 
       59 
53 
     | 
    
         
             
                        type.new(
         
     | 
| 
       60 
54 
     | 
    
         
             
                          name,
         
     | 
| 
       61 
     | 
    
         
            -
                          options.fetch(: 
     | 
| 
       62 
     | 
    
         
            -
                          options.fetch(: 
     | 
| 
       63 
     | 
    
         
            -
                          options.fetch(: 
     | 
| 
       64 
     | 
    
         
            -
                          options.reject         {|k,v| [:as, :mapper, :links].include?(k) }
         
     | 
| 
      
 55 
     | 
    
         
            +
                          options.fetch(:mapper)            { Undefined },
         
     | 
| 
      
 56 
     | 
    
         
            +
                          options.fetch(:rel)               { Undefined },
         
     | 
| 
      
 57 
     | 
    
         
            +
                          options.fetch(:collection_mapper) { Undefined },
         
     | 
| 
       65 
58 
     | 
    
         
             
                        )
         
     | 
| 
       66 
     | 
    
         
            -
                       
     | 
| 
      
 59 
     | 
    
         
            +
                      ]
         
     | 
| 
       67 
60 
     | 
    
         
             
                    )
         
     | 
| 
       68 
61 
     | 
    
         
             
                  end
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
                  def links
         
     | 
| 
       71 
     | 
    
         
            -
                    @links
         
     | 
| 
       72 
     | 
    
         
            -
                  end
         
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
                  def associations
         
     | 
| 
       75 
     | 
    
         
            -
                    @associations
         
     | 
| 
       76 
     | 
    
         
            -
                  end
         
     | 
| 
       77 
62 
     | 
    
         
             
                end
         
     | 
| 
       78 
63 
     | 
    
         
             
              end
         
     | 
| 
       79 
64 
     | 
    
         
             
            end
         
     | 
    
        data/lib/yaks/mapper/has_many.rb
    CHANGED
    
    | 
         @@ -1,14 +1,15 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Yaks
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Mapper
         
     | 
| 
       3 
3 
     | 
    
         
             
                class HasMany < Association
         
     | 
| 
       4 
     | 
    
         
            -
                  def map_resource(collection,  
     | 
| 
       5 
     | 
    
         
            -
                     
     | 
| 
       6 
     | 
    
         
            -
                     
     | 
| 
      
 4 
     | 
    
         
            +
                  def map_resource(collection, context)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    resource_mapper = association_mapper(context.fetch(:policy))
         
     | 
| 
      
 6 
     | 
    
         
            +
                    context         = context.merge(resource_mapper: resource_mapper)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    collection_mapper.new(collection, context).to_resource
         
     | 
| 
       7 
8 
     | 
    
         
             
                  end
         
     | 
| 
       8 
9 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
                  def collection_mapper 
     | 
| 
       10 
     | 
    
         
            -
                     
     | 
| 
       11 
     | 
    
         
            -
                     
     | 
| 
      
 10 
     | 
    
         
            +
                  def collection_mapper
         
     | 
| 
      
 11 
     | 
    
         
            +
                    return @collection_mapper unless @collection_mapper.equal? Undefined
         
     | 
| 
      
 12 
     | 
    
         
            +
                    CollectionMapper
         
     | 
| 
       12 
13 
     | 
    
         
             
                  end
         
     | 
| 
       13 
14 
     | 
    
         
             
                end
         
     | 
| 
       14 
15 
     | 
    
         
             
              end
         
     | 
    
        data/lib/yaks/mapper/has_one.rb
    CHANGED
    
    | 
         @@ -1,9 +1,10 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Yaks
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Mapper
         
     | 
| 
       3 
3 
     | 
    
         
             
                class HasOne < Association
         
     | 
| 
       4 
     | 
    
         
            -
                  def map_resource(instance,  
     | 
| 
       5 
     | 
    
         
            -
                     
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
      
 4 
     | 
    
         
            +
                  def map_resource(instance, context)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    association_mapper(context.fetch(:policy))
         
     | 
| 
      
 6 
     | 
    
         
            +
                      .new(instance, context)
         
     | 
| 
      
 7 
     | 
    
         
            +
                      .to_resource
         
     | 
| 
       7 
8 
     | 
    
         
             
                  end
         
     | 
| 
       8 
9 
     | 
    
         
             
                end
         
     | 
| 
       9 
10 
     | 
    
         
             
              end
         
     | 
    
        data/lib/yaks/mapper/link.rb
    CHANGED
    
    | 
         @@ -1,95 +1,92 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Yaks
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Mapper
         
     | 
| 
      
 3 
     | 
    
         
            +
                # A Yaks::Mapper::Link is part of a mapper's configuration. It captures
         
     | 
| 
      
 4 
     | 
    
         
            +
                # what is set through the mapper's class level `#link` function, and is
         
     | 
| 
      
 5 
     | 
    
         
            +
                # capable of generating a `Yaks::Resource::Link` for a given mapper
         
     | 
| 
      
 6 
     | 
    
         
            +
                # instance (and hence subject).
         
     | 
| 
      
 7 
     | 
    
         
            +
                #
         
     | 
| 
      
 8 
     | 
    
         
            +
                # @example
         
     | 
| 
      
 9 
     | 
    
         
            +
                #   link :self, 'http://api.foo.org/users/{id}', title: ->{ "User #{object.name}" }
         
     | 
| 
      
 10 
     | 
    
         
            +
                #   link :profile, 'http://apidocs.foo.org/profiles/users'
         
     | 
| 
      
 11 
     | 
    
         
            +
                #   link 'http://apidocs.foo.org/rels/friends', 'http://api.foo.org/users/{id}/friends?page={page}', expand: [:id]
         
     | 
| 
      
 12 
     | 
    
         
            +
                #
         
     | 
| 
      
 13 
     | 
    
         
            +
                # It takes a relationship identifier, a URI template and an options hash.
         
     | 
| 
      
 14 
     | 
    
         
            +
                #
         
     | 
| 
      
 15 
     | 
    
         
            +
                # @param rel [Symbol|String] Either a registered relationship type (Symbol)
         
     | 
| 
      
 16 
     | 
    
         
            +
                #   or a relationship URI. See [RFC5988 Web Linking](http://tools.ietf.org/html/rfc5988)
         
     | 
| 
      
 17 
     | 
    
         
            +
                # @param template [String] A [RFC6570](http://tools.ietf.org/html/rfc6570) URI template
         
     | 
| 
      
 18 
     | 
    
         
            +
                # @param template [Symbol] A method name that generates the link. No more expansion is done afterwards
         
     | 
| 
      
 19 
     | 
    
         
            +
                # @option expand [Boolean] pass false to pass on the URI template in the response,
         
     | 
| 
      
 20 
     | 
    
         
            +
                #   instead of expanding the variables
         
     | 
| 
      
 21 
     | 
    
         
            +
                # @option expand [Array[Symbol]] pass a list of variable names to only expand those,
         
     | 
| 
      
 22 
     | 
    
         
            +
                #   and return a partially expanded URI template in the response
         
     | 
| 
      
 23 
     | 
    
         
            +
                # @option title [String] Give the link a title
         
     | 
| 
      
 24 
     | 
    
         
            +
                # @option title [#to_proc] Block that returns the title. If it takes an argument,
         
     | 
| 
      
 25 
     | 
    
         
            +
                #   it will receive the mapper instance as argument. Otherwise it is evaluated in the mapper context
         
     | 
| 
       3 
26 
     | 
    
         
             
                class Link
         
     | 
| 
       4 
27 
     | 
    
         
             
                  extend Forwardable
         
     | 
| 
       5 
28 
     | 
    
         
             
                  include Concord.new(:rel, :template, :options)
         
     | 
| 
       6 
29 
     | 
    
         
             
                  include Util
         
     | 
| 
       7 
30 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                  def_delegators :uri_template, : 
     | 
| 
      
 31 
     | 
    
         
            +
                  def_delegators :uri_template, :expand_partial
         
     | 
| 
       9 
32 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                  def initialize(rel, template, options 
     | 
| 
      
 33 
     | 
    
         
            +
                  def initialize(rel, template, options)
         
     | 
| 
       11 
34 
     | 
    
         
             
                    @rel, @template, @options = rel, template, options
         
     | 
| 
       12 
35 
     | 
    
         
             
                  end
         
     | 
| 
       13 
36 
     | 
    
         | 
| 
       14 
37 
     | 
    
         
             
                  def rel?(rel)
         
     | 
| 
       15 
     | 
    
         
            -
                     
     | 
| 
      
 38 
     | 
    
         
            +
                    rel().eql? rel
         
     | 
| 
       16 
39 
     | 
    
         
             
                  end
         
     | 
| 
       17 
40 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
                   
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
      
 41 
     | 
    
         
            +
                  # A link is templated if it does not expand, or only partially
         
     | 
| 
      
 42 
     | 
    
         
            +
                  def templated?
         
     | 
| 
      
 43 
     | 
    
         
            +
                    !options.fetch(:expand) { true }.equal? true
         
     | 
| 
       20 
44 
     | 
    
         
             
                  end
         
     | 
| 
       21 
     | 
    
         
            -
                  alias expand? expand
         
     | 
| 
       22 
45 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
                  # link  
     | 
| 
       24 
     | 
    
         
            -
                  def  
     | 
| 
       25 
     | 
    
         
            -
                     
     | 
| 
      
 46 
     | 
    
         
            +
                  # Does this link need expansion, full or partially
         
     | 
| 
      
 47 
     | 
    
         
            +
                  def expand?
         
     | 
| 
      
 48 
     | 
    
         
            +
                    options.fetch(:expand) { true }
         
     | 
| 
       26 
49 
     | 
    
         
             
                  end
         
     | 
| 
       27 
50 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
                  def  
     | 
| 
       29 
     | 
    
         
            -
                     
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                    # link 'http://link/{template}', expand: false
         
     | 
| 
       33 
     | 
    
         
            -
                    # link 'http://link/{template}', expand: [:only, :some, :fields]
         
     | 
| 
       34 
     | 
    
         
            -
                    return template unless expand?
         
     | 
| 
      
 51 
     | 
    
         
            +
                  def template_variables
         
     | 
| 
      
 52 
     | 
    
         
            +
                    options.fetch(:expand) { uri_template.variables }.map(&:to_sym)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
       35 
54 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                      uri_template.expand(expansion_mapping(lookup))
         
     | 
| 
      
 55 
     | 
    
         
            +
                  def expansion_mapping(lookup)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    template_variables.map.with_object({}) do |name, hsh|
         
     | 
| 
      
 57 
     | 
    
         
            +
                      hsh[name] = lookup[name]
         
     | 
| 
       40 
58 
     | 
    
         
             
                    end
         
     | 
| 
       41 
59 
     | 
    
         
             
                  end
         
     | 
| 
       42 
60 
     | 
    
         | 
| 
      
 61 
     | 
    
         
            +
                  def uri_template
         
     | 
| 
      
 62 
     | 
    
         
            +
                    URITemplate.new(template)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
       43 
65 
     | 
    
         
             
                  def map_to_resource_link(mapper)
         
     | 
| 
       44 
     | 
    
         
            -
                     
     | 
| 
      
 66 
     | 
    
         
            +
                    Resource::Link.new(
         
     | 
| 
       45 
67 
     | 
    
         
             
                      rel,
         
     | 
| 
       46 
68 
     | 
    
         
             
                      expand_with(mapper.method(:load_attribute)),
         
     | 
| 
       47 
69 
     | 
    
         
             
                      resource_link_options(mapper)
         
     | 
| 
       48 
70 
     | 
    
         
             
                    )
         
     | 
| 
       49 
71 
     | 
    
         
             
                  end
         
     | 
| 
       50 
72 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
                  def  
     | 
| 
       52 
     | 
    
         
            -
                     
     | 
| 
       53 
     | 
    
         
            -
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  def expand_with(lookup)
         
     | 
| 
      
 74 
     | 
    
         
            +
                    return lookup[template] if template.is_a? Symbol
         
     | 
| 
       54 
75 
     | 
    
         | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
                      uri_template.variables & expand.map(&:to_s)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    if expand?
         
     | 
| 
      
 77 
     | 
    
         
            +
                      expand_partial(expansion_mapping(lookup)).to_s
         
     | 
| 
       58 
78 
     | 
    
         
             
                    else
         
     | 
| 
       59 
     | 
    
         
            -
                       
     | 
| 
      
 79 
     | 
    
         
            +
                      template
         
     | 
| 
       60 
80 
     | 
    
         
             
                    end
         
     | 
| 
       61 
81 
     | 
    
         
             
                  end
         
     | 
| 
       62 
82 
     | 
    
         | 
| 
       63 
     | 
    
         
            -
                  def expansion_mapping(lookup)
         
     | 
| 
       64 
     | 
    
         
            -
                    template_variables.map.with_object({}) do |var, hsh|
         
     | 
| 
       65 
     | 
    
         
            -
                      hsh[var] = lookup.call(var)
         
     | 
| 
       66 
     | 
    
         
            -
                    end
         
     | 
| 
       67 
     | 
    
         
            -
                  end
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
                  # Link properties defined in HAL
         
     | 
| 
       70 
     | 
    
         
            -
                  # href
         
     | 
| 
       71 
     | 
    
         
            -
                  # templated
         
     | 
| 
       72 
     | 
    
         
            -
                  # typed
         
     | 
| 
       73 
     | 
    
         
            -
                  # deprecation
         
     | 
| 
       74 
     | 
    
         
            -
                  # name
         
     | 
| 
       75 
     | 
    
         
            -
                  # profile
         
     | 
| 
       76 
     | 
    
         
            -
                  # title
         
     | 
| 
       77 
     | 
    
         
            -
                  # hreflang
         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
83 
     | 
    
         
             
                  def resource_link_options(mapper)
         
     | 
| 
       80 
     | 
    
         
            -
                    options =  
     | 
| 
       81 
     | 
    
         
            -
                    options = options.merge(title:  
     | 
| 
       82 
     | 
    
         
            -
                    options = options.merge( 
     | 
| 
       83 
     | 
    
         
            -
                    options.reject{| 
     | 
| 
      
 84 
     | 
    
         
            +
                    options = options()
         
     | 
| 
      
 85 
     | 
    
         
            +
                    options = options.merge(title: Resolve(options[:title], mapper)) if options.key?(:title)
         
     | 
| 
      
 86 
     | 
    
         
            +
                    options = options.merge(templated: true) if templated?
         
     | 
| 
      
 87 
     | 
    
         
            +
                    options.reject{|key| key.equal? :expand }
         
     | 
| 
       84 
88 
     | 
    
         
             
                  end
         
     | 
| 
       85 
89 
     | 
    
         | 
| 
       86 
     | 
    
         
            -
                  def resolve_title(title_proc, mapper)
         
     | 
| 
       87 
     | 
    
         
            -
                    Resolve(title_proc, mapper)
         
     | 
| 
       88 
     | 
    
         
            -
                  end
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
                  def make_resource_link(rel, uri, options)
         
     | 
| 
       91 
     | 
    
         
            -
                    Resource::Link.new(rel, uri, options)
         
     | 
| 
       92 
     | 
    
         
            -
                  end
         
     | 
| 
       93 
90 
     | 
    
         
             
                end
         
     | 
| 
       94 
91 
     | 
    
         
             
              end
         
     | 
| 
       95 
92 
     | 
    
         
             
            end
         
     | 
    
        data/lib/yaks/mapper.rb
    CHANGED
    
    | 
         @@ -3,61 +3,73 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module Yaks
         
     | 
| 
       4 
4 
     | 
    
         
             
              class Mapper
         
     | 
| 
       5 
5 
     | 
    
         
             
                extend ClassMethods, Forwardable
         
     | 
| 
       6 
     | 
    
         
            -
                include Util,  
     | 
| 
      
 6 
     | 
    
         
            +
                include Util, FP
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                def_delegators 'self.class', :config
         
     | 
| 
       9 
9 
     | 
    
         
             
                def_delegators :config, :attributes, :links, :associations
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
                attr_reader : 
     | 
| 
       12 
     | 
    
         
            -
                private :subject, :options
         
     | 
| 
       13 
     | 
    
         
            -
                alias object subject
         
     | 
| 
      
 11 
     | 
    
         
            +
                attr_reader :object, :context
         
     | 
| 
       14 
12 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
                def initialize( 
     | 
| 
       16 
     | 
    
         
            -
                  @ 
     | 
| 
       17 
     | 
    
         
            -
                  @ 
     | 
| 
      
 13 
     | 
    
         
            +
                def initialize(object, context)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @object  = object
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @context = context
         
     | 
| 
       18 
16 
     | 
    
         
             
                end
         
     | 
| 
       19 
17 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
                def  
     | 
| 
       21 
     | 
    
         
            -
                   
     | 
| 
      
 18 
     | 
    
         
            +
                def policy
         
     | 
| 
      
 19 
     | 
    
         
            +
                  context.fetch(:policy)
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def env
         
     | 
| 
      
 23 
     | 
    
         
            +
                  context.fetch(:env)
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def call
         
     | 
| 
      
 27 
     | 
    
         
            +
                  return NullResource.new if object.nil?
         
     | 
| 
       22 
28 
     | 
    
         | 
| 
       23 
29 
     | 
    
         
             
                  Resource.new(
         
     | 
| 
       24 
     | 
    
         
            -
                     
     | 
| 
       25 
     | 
    
         
            -
                     
     | 
| 
       26 
     | 
    
         
            -
                     
     | 
| 
      
 30 
     | 
    
         
            +
                    type:         mapper_name,
         
     | 
| 
      
 31 
     | 
    
         
            +
                    attributes:   map_attributes,
         
     | 
| 
      
 32 
     | 
    
         
            +
                    links:        map_links,
         
     | 
| 
      
 33 
     | 
    
         
            +
                    subresources: map_subresources
         
     | 
| 
       27 
34 
     | 
    
         
             
                  )
         
     | 
| 
       28 
35 
     | 
    
         
             
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
                alias to_resource call
         
     | 
| 
       29 
37 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
                def  
     | 
| 
       31 
     | 
    
         
            -
                   
     | 
| 
      
 38 
     | 
    
         
            +
                def map_attributes
         
     | 
| 
      
 39 
     | 
    
         
            +
                  filter(attributes).each_with_object({}) do |attr, memo|
         
     | 
| 
      
 40 
     | 
    
         
            +
                    memo[attr] = load_attribute(attr)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
       32 
42 
     | 
    
         
             
                end
         
     | 
| 
       33 
43 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                def  
     | 
| 
       35 
     | 
    
         
            -
                   
     | 
| 
      
 44 
     | 
    
         
            +
                def map_links
         
     | 
| 
      
 45 
     | 
    
         
            +
                  links.map &send_with_args(:map_to_resource_link, self)
         
     | 
| 
       36 
46 
     | 
    
         
             
                end
         
     | 
| 
       37 
47 
     | 
    
         | 
| 
       38 
48 
     | 
    
         
             
                def map_subresources
         
     | 
| 
       39 
     | 
    
         
            -
                  attributes 
     | 
| 
       40 
     | 
    
         
            -
                  associations.select{|assoc| attributes.include? assoc.name} 
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
      
 49 
     | 
    
         
            +
                  attributes   = filter(associations.map(&:name))
         
     | 
| 
      
 50 
     | 
    
         
            +
                  associations = associations().select{|assoc| attributes.include? assoc.name }
         
     | 
| 
      
 51 
     | 
    
         
            +
                  associations.each_with_object({}) do |association, memo|
         
     | 
| 
      
 52 
     | 
    
         
            +
                    rel, subresource = association.create_subresource(
         
     | 
| 
      
 53 
     | 
    
         
            +
                      self,
         
     | 
| 
       43 
54 
     | 
    
         
             
                      method(:load_association),
         
     | 
| 
       44 
     | 
    
         
            -
                       
     | 
| 
      
 55 
     | 
    
         
            +
                      context
         
     | 
| 
       45 
56 
     | 
    
         
             
                    )
         
     | 
| 
      
 57 
     | 
    
         
            +
                    memo[rel] = subresource
         
     | 
| 
       46 
58 
     | 
    
         
             
                  end
         
     | 
| 
       47 
59 
     | 
    
         
             
                end
         
     | 
| 
       48 
60 
     | 
    
         | 
| 
       49 
61 
     | 
    
         
             
                def load_attribute(name)
         
     | 
| 
       50 
     | 
    
         
            -
                  respond_to?(name) ?  
     | 
| 
      
 62 
     | 
    
         
            +
                  respond_to?(name) ? public_send(name) : object.public_send(name)
         
     | 
| 
       51 
63 
     | 
    
         
             
                end
         
     | 
| 
       52 
64 
     | 
    
         
             
                alias load_association load_attribute
         
     | 
| 
       53 
65 
     | 
    
         | 
| 
       54 
     | 
    
         
            -
                def profile
         
     | 
| 
       55 
     | 
    
         
            -
                  config.profile || policy.derive_missing_profile_from_mapper(self)
         
     | 
| 
       56 
     | 
    
         
            -
                end
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
66 
     | 
    
         
             
                def filter(attrs)
         
     | 
| 
       59 
67 
     | 
    
         
             
                  attrs
         
     | 
| 
       60 
68 
     | 
    
         
             
                end
         
     | 
| 
       61 
69 
     | 
    
         | 
| 
      
 70 
     | 
    
         
            +
                def mapper_name
         
     | 
| 
      
 71 
     | 
    
         
            +
                  config.type || policy.derive_type_from_mapper_class(self.class)
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
       62 
74 
     | 
    
         
             
              end
         
     | 
| 
       63 
75 
     | 
    
         
             
            end
         
     | 
    
        data/lib/yaks/null_resource.rb
    CHANGED
    
    
    
        data/lib/yaks/primitivize.rb
    CHANGED
    
    | 
         @@ -1,43 +1,45 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Yaks
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Primitivize
         
     | 
| 
       3 
     | 
    
         
            -
                include Concord.new(:object)
         
     | 
| 
       4 
3 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
                 
     | 
| 
       6 
     | 
    
         
            -
                MAPPINGS = {}
         
     | 
| 
      
 4 
     | 
    
         
            +
                attr_reader :mappings
         
     | 
| 
       7 
5 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                def  
     | 
| 
       9 
     | 
    
         
            -
                   
     | 
| 
      
 6 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @mappings = {}
         
     | 
| 
       10 
8 
     | 
    
         
             
                end
         
     | 
| 
       11 
9 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
                def  
     | 
| 
       13 
     | 
    
         
            -
                   
     | 
| 
       14 
     | 
    
         
            -
                     
     | 
| 
      
 10 
     | 
    
         
            +
                def call(object)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  mappings.each do |pattern, block|
         
     | 
| 
      
 12 
     | 
    
         
            +
                    return instance_exec(object, &block) if pattern === object
         
     | 
| 
       15 
13 
     | 
    
         
             
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                  raise "don't know how to turn #{object.class} (#{object.inspect}) into a primitive"
         
     | 
| 
       16 
15 
     | 
    
         
             
                end
         
     | 
| 
       17 
16 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
                map 
     | 
| 
       19 
     | 
    
         
            -
                   
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                map Symbol do
         
     | 
| 
       23 
     | 
    
         
            -
                  object.to_s
         
     | 
| 
       24 
     | 
    
         
            -
                end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                map Hash, Hamster::Hash do
         
     | 
| 
       27 
     | 
    
         
            -
                  object.to_enum(:each).with_object({}) do |(key, value), output|
         
     | 
| 
       28 
     | 
    
         
            -
                    output[self.class.(key)] = self.class.(value)
         
     | 
| 
      
 17 
     | 
    
         
            +
                def map(*types, &blk)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  types.each do |type|
         
     | 
| 
      
 19 
     | 
    
         
            +
                    mappings[type] = blk
         
     | 
| 
       29 
20 
     | 
    
         
             
                  end
         
     | 
| 
       30 
21 
     | 
    
         
             
                end
         
     | 
| 
       31 
22 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
                 
     | 
| 
       33 
     | 
    
         
            -
                   
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
                     
     | 
| 
      
 23 
     | 
    
         
            +
                def self.create
         
     | 
| 
      
 24 
     | 
    
         
            +
                  new.tap do |p|
         
     | 
| 
      
 25 
     | 
    
         
            +
                    p.map String, TrueClass, FalseClass, NilClass, Numeric do |object|
         
     | 
| 
      
 26 
     | 
    
         
            +
                      object
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    p.map Symbol do |object|
         
     | 
| 
      
 30 
     | 
    
         
            +
                      object.to_s
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    p.map Hash do |object|
         
     | 
| 
      
 34 
     | 
    
         
            +
                      object.to_enum(:each).with_object({}) do |(key, value), output|
         
     | 
| 
      
 35 
     | 
    
         
            +
                        output[call(key)] = call(value)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      end
         
     | 
| 
      
 37 
     | 
    
         
            +
                    end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    p.map Enumerable do |object|
         
     | 
| 
      
 40 
     | 
    
         
            +
                      object.map(&method(:call)).to_a
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
       39 
42 
     | 
    
         
             
                  end
         
     | 
| 
       40 
     | 
    
         
            -
                  raise "don't know how to turn #{object.class} (#{object.inspect}) into a primitive"
         
     | 
| 
       41 
43 
     | 
    
         
             
                end
         
     | 
| 
       42 
44 
     | 
    
         
             
              end
         
     | 
| 
       43 
45 
     | 
    
         
             
            end
         
     | 
    
        data/lib/yaks/resource/link.rb
    CHANGED
    
    
    
        data/lib/yaks/resource.rb
    CHANGED
    
    | 
         @@ -1,20 +1,24 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Yaks
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Resource
         
     | 
| 
       3 
     | 
    
         
            -
                include Equalizer.new(:links, :attributes, :subresources)
         
     | 
| 
       4 
     | 
    
         
            -
                include Enumerable 
     | 
| 
      
 3 
     | 
    
         
            +
                include Equalizer.new(:type, :links, :attributes, :subresources)
         
     | 
| 
      
 4 
     | 
    
         
            +
                include Enumerable
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
                attr_reader :attributes, :links, :subresources
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_reader :type, :attributes, :links, :subresources
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                def initialize( 
     | 
| 
       9 
     | 
    
         
            -
                  @ 
     | 
| 
       10 
     | 
    
         
            -
                  @ 
     | 
| 
       11 
     | 
    
         
            -
                  @ 
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize(options)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @type         = options.fetch(:type, nil)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @attributes   = options.fetch(:attributes, {})
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @links        = options.fetch(:links, [])
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @subresources = options.fetch(:subresources, {})
         
     | 
| 
       12 
13 
     | 
    
         
             
                end
         
     | 
| 
       13 
14 
     | 
    
         | 
| 
       14 
15 
     | 
    
         
             
                def [](attr)
         
     | 
| 
       15 
16 
     | 
    
         
             
                  attributes[attr]
         
     | 
| 
       16 
17 
     | 
    
         
             
                end
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
      
 19 
     | 
    
         
            +
                # def type
         
     | 
| 
      
 20 
     | 
    
         
            +
                # end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
       18 
22 
     | 
    
         
             
                def each
         
     | 
| 
       19 
23 
     | 
    
         
             
                  return to_enum unless block_given?
         
     | 
| 
       20 
24 
     | 
    
         
             
                  yield self
         
     | 
| 
         @@ -23,5 +27,12 @@ module Yaks 
     | 
|
| 
       23 
27 
     | 
    
         
             
                def collection?
         
     | 
| 
       24 
28 
     | 
    
         
             
                  false
         
     | 
| 
       25 
29 
     | 
    
         
             
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def self_link
         
     | 
| 
      
 32 
     | 
    
         
            +
                  links.find do |link|
         
     | 
| 
      
 33 
     | 
    
         
            +
                    link.rel == :self
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
       26 
37 
     | 
    
         
             
              end
         
     | 
| 
       27 
38 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Yaks
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Serializer
         
     | 
| 
      
 3 
     | 
    
         
            +
                class CollectionJson < self
         
     | 
| 
      
 4 
     | 
    
         
            +
                  Serializer.register self, :collection_json, 'application/vnd.collection+json'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  include FP
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def serialize_resource(resource)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    result = {
         
     | 
| 
      
 10 
     | 
    
         
            +
                      version: "1.0",
         
     | 
| 
      
 11 
     | 
    
         
            +
                      items: serialize_items(resource)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    }
         
     | 
| 
      
 13 
     | 
    
         
            +
                    result[:href] = resource.self_link.uri if resource.self_link
         
     | 
| 
      
 14 
     | 
    
         
            +
                    {collection: result}
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def serialize_items(resource)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    resource.map do |item|
         
     | 
| 
      
 19 
     | 
    
         
            +
                      attrs = item.attributes.map do |name, value|
         
     | 
| 
      
 20 
     | 
    
         
            +
                        {
         
     | 
| 
      
 21 
     | 
    
         
            +
                          name: name,
         
     | 
| 
      
 22 
     | 
    
         
            +
                          value: value
         
     | 
| 
      
 23 
     | 
    
         
            +
                        }
         
     | 
| 
      
 24 
     | 
    
         
            +
                      end
         
     | 
| 
      
 25 
     | 
    
         
            +
                      result = { data: attrs }
         
     | 
| 
      
 26 
     | 
    
         
            +
                      result[:href] = item.self_link.uri if item.self_link
         
     | 
| 
      
 27 
     | 
    
         
            +
                      item.links.each do |link|
         
     | 
| 
      
 28 
     | 
    
         
            +
                        next if link.rel == :self
         
     | 
| 
      
 29 
     | 
    
         
            +
                        result[:links] ||= []
         
     | 
| 
      
 30 
     | 
    
         
            +
                        result[:links] << {rel: link.rel, href: link.uri}
         
     | 
| 
      
 31 
     | 
    
         
            +
                        result[:links].last[:name] = link.name if link.name
         
     | 
| 
      
 32 
     | 
    
         
            +
                      end
         
     | 
| 
      
 33 
     | 
    
         
            +
                      result
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     |