conglomerate 0.10.0 → 0.11.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dac49f10d492b562ad8a9e9e01dd510d1e153f4d
4
- data.tar.gz: 2135e7554e814fed47ab509555027451703e01f6
3
+ metadata.gz: 299095559c8ba18987524ef7e2702c2f2ad341b6
4
+ data.tar.gz: 65a914ac9c9c2a31086c39d1577685347339b568
5
5
  SHA512:
6
- metadata.gz: d5e31a22776e551119a344bad716c5bc79d09de0de18ce939e22e624b79b96b1ab37a5bb611cf13664b2d8e17cc7ef9d65a6295df45601f836f260ca0851170e
7
- data.tar.gz: 7215b0dae33f4acaef3549d2a4ab39f87abd94a91f2caea55e4392a4c46209b9d2cdbf63184aad1a6360e0af5820438450dcbaac6036c7bd4a5cef38ba5b0f8c
6
+ metadata.gz: 2374f028927ee394aabeb148a0513c9dd2b1a59e9cd3c68a926c98c9bd1b12391ad13d19c39eccabdc7cf9e56dd446c9c0f1a31dbe2451bd2d430a348f0efa1d
7
+ data.tar.gz: 9a7c73782ab8de2f30131cc60f5449941159b3168b5c228e1af4810f12a49372cd18265e7a3170712c592bd0b288f6324bb0eb45c8fb3d76cdb180f482c57a18
data/README.md CHANGED
@@ -1,8 +1,7 @@
1
1
  # Conglomerate
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/conglomerate.png)](http://badge.fury.io/rb/conglomerate)
4
- [![Semaphore](https://semaphoreapp.com/api/v1/projects/7b914dac-6aa6-43dd-94a9-53698ef1922a/120842/shields_badge.png
5
- )](https://semaphoreapp.com/minter/conglomerate)
4
+ [ ![Codeship Status for teamsnap/conglomerate](https://www.codeship.io/projects/7210a3f0-de00-0131-af05-5236ebb52643/status)](https://www.codeship.io/projects/24758)
6
5
  [![Code Climate](https://codeclimate.com/github/teamsnap/conglomerate.png)](https://codeclimate.com/github/teamsnap/conglomerate)
7
6
  [![Coverage Status](https://coveralls.io/repos/teamsnap/conglomerate/badge.png?branch=master)](https://coveralls.io/r/teamsnap/conglomerate?branch=master)
8
7
  [![Dependency Status](https://gemnasium.com/teamsnap/conglomerate.png)](https://gemnasium.com/teamsnap/conglomerate)
@@ -36,20 +35,29 @@ Or install it yourself as:
36
35
  ```ruby
37
36
  # Step 1: Create a serializer
38
37
  class TeamSerializer
39
- include Conglomerate.serializer
38
+ include Conglomerate::RootBuilder
40
39
 
41
40
  href { teams_url }
42
- item_href { |item| team_url(item.id) }
43
41
 
44
- attribute :id
45
- attribute :name, :template => true
46
- attribute :event_ids, :rel => :events { |item| event_url(item.event_ids.join(",")) }
42
+ item "Team" do |item|
43
+ href { team_url(item.id) }
47
44
 
48
- link :root { root_url }
45
+ datum :id
46
+ datum :name
47
+ datum :event_ids
49
48
 
50
- query :search, :data => :id { search_teams_url }
49
+ link :events, :href => Proc.new { event_url(item.event_ids.join(",")) }
50
+ end
51
+
52
+ link :root, :href => Proc.new { root_url }
53
+
54
+ query :search, :href => Proc.new { search_items_url } do
55
+ datum :id
56
+ end
51
57
 
52
- command :populate, :data => :id { populate_teams_url }
58
+ template do
59
+ datum :name
60
+ end
53
61
  end
54
62
 
55
63
  # Step 2: Serialize any object
@@ -107,15 +115,6 @@ end
107
115
  ]
108
116
  }
109
117
  ],
110
- "commands": [
111
- {
112
- "rel": "populate",
113
- "href": "http://example.com/teams/populate",
114
- "data": [
115
- {"name": "id", "value": ""}
116
- ]
117
- }
118
- ],
119
118
  "template": {
120
119
  "data": [
121
120
  {"name": "name", "value": ""}
data/lib/conglomerate.rb CHANGED
@@ -11,6 +11,20 @@ require_relative "conglomerate/query"
11
11
  require_relative "conglomerate/command"
12
12
  require_relative "conglomerate/collection"
13
13
  require_relative "conglomerate/tree_deserializer"
14
+ require_relative "conglomerate/root"
15
+
16
+ require_relative "conglomerate/mixin_ivar_helper"
17
+ require_relative "conglomerate/builder_call"
18
+
19
+ require_relative "conglomerate/builder_serializer"
20
+ require_relative "conglomerate/particle_builder"
21
+ require_relative "conglomerate/link_builder"
22
+ require_relative "conglomerate/datum_builder"
23
+ require_relative "conglomerate/query_builder"
24
+ require_relative "conglomerate/template_builder"
25
+ require_relative "conglomerate/item_builder"
26
+ require_relative "conglomerate/collection_builder"
27
+ require_relative "conglomerate/root_builder"
14
28
 
15
29
  module Conglomerate
16
30
  def self.serialize(serializable)
@@ -0,0 +1,87 @@
1
+ module Conglomerate
2
+ class BuilderCall
3
+ attr_accessor :name, :opts, :block, :builder, :array, :iterates
4
+
5
+ def initialize(name: nil, opts: {}, block:, builder:, array:, iterates:)
6
+ self.name = name
7
+ self.opts = opts
8
+ self.block = block
9
+ self.builder = builder
10
+ self.array = array
11
+ self.iterates = iterates
12
+ end
13
+
14
+ def run(context, objects, attrs, attr_name)
15
+ BuilderCallInstance.new(self, context, objects, attrs, attr_name).run
16
+ end
17
+
18
+ private
19
+
20
+ class BuilderCallInstance
21
+ extend Forwardable
22
+
23
+ attr_accessor :bc, :context, :objects, :attrs, :attr_name
24
+
25
+ delegate [:name, :opts, :block, :builder, :array, :iterates] => :bc
26
+
27
+ def initialize(bc, context, objects, attrs, attr_name)
28
+ self.bc = bc
29
+ self.context = context
30
+ self.objects = objects
31
+ self.attrs = attrs
32
+ self.attr_name = attr_name
33
+ end
34
+
35
+ def run
36
+ return unless should_run?
37
+
38
+ if iterates
39
+ attrs[attr_name] ||= []
40
+
41
+ objects.each do |item|
42
+ attrs[attr_name] << invoke(item)
43
+ end
44
+ elsif array
45
+ attrs[attr_name] ||= []
46
+ attrs[attr_name] << invoke
47
+ else
48
+ attrs[attr_name] = invoke
49
+ end
50
+ end
51
+
52
+ def invoke(item = nil)
53
+ serializer = builder.serializer
54
+ builder_klass = Class.new do
55
+ include serializer
56
+ end
57
+
58
+ if item
59
+ builder_klass.class_exec(item, &block) if block
60
+ else
61
+ builder_klass.class_eval(&block) if block
62
+ end
63
+
64
+ builder = builder_klass.new(objects, :name => name, :context => context)
65
+
66
+ attrs = {}
67
+
68
+ opts.each do |key, value|
69
+ attrs[key] = value_from_proc(value)
70
+ end
71
+
72
+ builder.build(attrs)
73
+ end
74
+
75
+ def value_from_proc(value)
76
+ value = context.instance_eval(&value) if value.respond_to?(:call)
77
+ value
78
+ end
79
+
80
+ private
81
+
82
+ def should_run?
83
+ !opts[:if] || (opts[:if] && opts[:if].call)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,78 @@
1
+ module Conglomerate
2
+ module BuilderSerializer
3
+ include Conglomerate::MixinIvarHelper
4
+
5
+ mi_ivar_accessor :objects, :context, :_builder_name
6
+
7
+ def initialize(objects, name: nil, context: nil)
8
+ self.objects = [*objects].compact
9
+ self.context = context
10
+ self._builder_name = name.to_s
11
+ end
12
+
13
+ def build(attrs = {})
14
+ internal_build(attrs)
15
+ end
16
+
17
+ def serialize
18
+ Conglomerate.serialize(build)
19
+ end
20
+
21
+ private
22
+
23
+ attr_accessor :object
24
+
25
+ def internal_build(attrs = {})
26
+ builder_values.each do |name|
27
+ value = get_class_value(name)
28
+ value = value_from_proc(value)
29
+ attrs[name.to_sym] = value if attrs[name.to_sym] == nil
30
+ end
31
+
32
+ builder_builders.each do |b|
33
+ run_builder_calls(b, attrs)
34
+ end
35
+
36
+ self.object = builder_type.new(attrs)
37
+
38
+ object
39
+ end
40
+
41
+ def run_builder_calls(b, attrs)
42
+ calls = builder_calls[b[:command]] || []
43
+
44
+ calls.each do |call|
45
+ call.run(context, objects, attrs, b[:name])
46
+ end
47
+ end
48
+
49
+ def builder_type
50
+ self.class.instance_variable_get("@_builder_type")
51
+ end
52
+
53
+ def builder_values
54
+ self.class.instance_variable_get("@_builder_values")
55
+ end
56
+
57
+ def builder_calls
58
+ self.class.instance_variable_get("@_builder_calls")
59
+ end
60
+
61
+ def builder_builders
62
+ self.class.instance_variable_get("@_builder_builders")
63
+ end
64
+
65
+ def get_class_value(name)
66
+ self.class.instance_variable_get("@#{name}")
67
+ end
68
+
69
+ def value_from_proc(value)
70
+ value = context.instance_eval(&value) if value.respond_to?(:call)
71
+ value
72
+ end
73
+
74
+ def context
75
+ instance_variable_get("@context")
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,13 @@
1
+ module Conglomerate
2
+ module CollectionBuilder
3
+ include Conglomerate::ParticleBuilder
4
+
5
+ builds Conglomerate::Collection
6
+
7
+ value :href
8
+ builder :item, Conglomerate::ItemBuilder, :name => :items, :array => true, :iterates => true
9
+ builder :link, Conglomerate::LinkBuilder, :name => :links, :array => true
10
+ builder :query, Conglomerate::QueryBuilder, :name => :queries, :array => true
11
+ builder :template, Conglomerate::TemplateBuilder, :name => :template
12
+ end
13
+ end
@@ -3,7 +3,7 @@ module Conglomerate
3
3
  include Conglomerate::Particle
4
4
 
5
5
  attribute :name, :type => String, :required => true
6
- attribute :value
6
+ attribute :value, :cull => false
7
7
  attribute :prompt, :type => String
8
8
  end
9
9
  end
@@ -0,0 +1,25 @@
1
+ module Conglomerate
2
+ module DatumBuilder
3
+ include Conglomerate::ParticleBuilder
4
+
5
+ builds Conglomerate::Datum
6
+
7
+ module BuildOverride
8
+ def build(attrs = {})
9
+ item = objects.first
10
+ val = item.send(_builder_name) if item
11
+
12
+ attrs = {
13
+ :name => _builder_name,
14
+ :value => val
15
+ }.merge(attrs)
16
+
17
+ super(attrs)
18
+ end
19
+ end
20
+
21
+ value :name
22
+ value :value
23
+ value :prompt
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ module Conglomerate
2
+ class Command
3
+ include Conglomerate::Particle
4
+
5
+ attribute :href, :type => String, :required => true
6
+ attribute :rel, :type => String, :required => true
7
+ attribute :name, :type => String
8
+ attribute :prompt, :type => String
9
+
10
+ array :data, :contains => Datum
11
+ end
12
+
13
+ class CommandBuilder
14
+ include Conglomerate::ParticleBuilder
15
+
16
+ builds Conglomerate::Command
17
+
18
+ module BuildOverride
19
+ def build(attrs = {})
20
+ instance_variable_set("@objects", nil)
21
+ super(attrs.merge({
22
+ :rel => _builder_name
23
+ }))
24
+ end
25
+ end
26
+
27
+ value :href
28
+ value :rel
29
+ value :name
30
+ value :prompt
31
+
32
+ builder :datum, Conglomerate::DatumBuilder, :name => :data, :array => true
33
+ end
34
+ end
35
+
36
+ Conglomerate::CollectionBuilder.send(:builder, :command, Conglomerate::CommandBuilder, :name => :commands, :array => true)
@@ -0,0 +1,11 @@
1
+ module Conglomerate
2
+ module ItemBuilder
3
+ include Conglomerate::ParticleBuilder
4
+
5
+ builds Conglomerate::Item
6
+
7
+ value :href
8
+ builder :datum, Conglomerate::DatumBuilder, :name => :data, :array => true
9
+ builder :link, Conglomerate::LinkBuilder, :name => :links, :array => true
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module Conglomerate
2
+ module LinkBuilder
3
+ include Conglomerate::ParticleBuilder
4
+
5
+ builds Conglomerate::Link
6
+
7
+ module BuildOverride
8
+ def build(attrs = {})
9
+ super(attrs.merge({
10
+ :rel => _builder_name
11
+ }))
12
+ end
13
+ end
14
+
15
+ value :href
16
+ value :rel
17
+ value :name
18
+ value :render
19
+ value :prompt
20
+ end
21
+ end
@@ -0,0 +1,53 @@
1
+ module Conglomerate
2
+ module MixinIvarHelper
3
+ def self.included(klass)
4
+ klass.send(:extend, ClassMethods)
5
+ end
6
+
7
+ private
8
+
9
+ module ClassMethods
10
+ def mc_ivar_writer(*names)
11
+ names.each do |name|
12
+ self.send(:define_singleton_method, "#{name}=") do |val|
13
+ instance_variable_set("@#{name}", val)
14
+ end
15
+ end
16
+ end
17
+
18
+ def mc_ivar_reader(*names)
19
+ names.each do |name|
20
+ self.send(:define_singleton_method,name) do
21
+ instance_variable_get("@#{name}")
22
+ end
23
+ end
24
+ end
25
+
26
+ def mi_ivar_writer(*names)
27
+ names.each do |name|
28
+ self.send(:define_method, "#{name}=") do |val|
29
+ instance_variable_set("@#{name}", val)
30
+ end
31
+ end
32
+ end
33
+
34
+ def mi_ivar_reader(*names)
35
+ names.each do |name|
36
+ self.send(:define_method,name) do
37
+ instance_variable_get("@#{name}")
38
+ end
39
+ end
40
+ end
41
+
42
+ def mc_ivar_accessor(*names)
43
+ mc_ivar_writer(*names)
44
+ mc_ivar_reader(*names)
45
+ end
46
+
47
+ def mi_ivar_accessor(*names)
48
+ mi_ivar_writer(*names)
49
+ mi_ivar_reader(*names)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -61,7 +61,7 @@ module Conglomerate
61
61
  attr_metadata = self.class.attributes[attr]
62
62
 
63
63
  if type = attr_metadata[:type]
64
- raise "TypeMismatch" if !val.is_a?(type)
64
+ raise "TypeMismatch" if !val.is_a?(type) && val != nil
65
65
  end
66
66
 
67
67
  self.instance_variable_set("@#{attr}", val)
@@ -0,0 +1,95 @@
1
+ module Conglomerate
2
+ module ParticleBuilder
3
+ def self.included(object)
4
+ object.send(:extend, ClassMethods)
5
+ end
6
+
7
+ private
8
+
9
+ def objects
10
+ instance_variable_get("@objects")
11
+ end
12
+
13
+ def name
14
+ instance_variable_get("@_builder_name").to_s
15
+ end
16
+
17
+ module ClassMethods
18
+ def self.extended(klass)
19
+ klass.instance_variable_set("@class_methods", Module.new)
20
+ klass.instance_variable_set("@values", [])
21
+ klass.instance_variable_set("@builders", [])
22
+ end
23
+
24
+ def serializer
25
+ mod = Module.new
26
+ mod.send(:include, Conglomerate::MixinIvarHelper)
27
+ mod.send(:mc_ivar_accessor, :class_methods, :values, :_builder_type, :_builder_calls, :_builder_builders, :build_override_mod)
28
+
29
+ mod.class_methods = class_methods
30
+ mod.values = values.dup
31
+ mod._builder_type = instance_variable_get("@type")
32
+ mod._builder_builders = builders.dup
33
+
34
+ begin
35
+ mod.build_override_mod = self::BuildOverride
36
+ rescue NameError
37
+ end
38
+
39
+ mod.define_singleton_method(:included) do |klass|
40
+ klass.send(:extend, class_methods)
41
+ klass.send(:include, Conglomerate::BuilderSerializer)
42
+ klass.send(:include, build_override_mod) if build_override_mod
43
+ klass.instance_variable_set("@_builder_values", values)
44
+ klass.instance_variable_set("@_builder_type", _builder_type)
45
+ klass.instance_variable_set("@_builder_calls", {})
46
+ klass.instance_variable_set("@_builder_builders", _builder_builders)
47
+ end
48
+ mod
49
+ end
50
+
51
+ private
52
+
53
+ include Conglomerate::MixinIvarHelper
54
+ mi_ivar_reader :values, :builders, :class_methods
55
+
56
+ def builds(type)
57
+ instance_variable_set("@type", type)
58
+ end
59
+
60
+ def value(name)
61
+ class_methods.send(:define_method, name) do |&block|
62
+ instance_variable_set("@#{name}", block)
63
+ end
64
+
65
+ values << name
66
+ end
67
+
68
+ def builder(command, builder, opts={})
69
+ name = opts[:name] || command
70
+ array = opts[:array] || false
71
+ iterates = opts[:iterates] || false
72
+
73
+ class_methods.send(:define_method, command) do |name=nil, opts={}, &block|
74
+ instance_variable_get("@_builder_calls")[command] ||= []
75
+ instance_variable_get("@_builder_calls")[command] << Conglomerate::BuilderCall.new({
76
+ :name => name,
77
+ :opts => opts,
78
+ :block => block,
79
+ :builder => builder,
80
+ :array => array,
81
+ :iterates => iterates
82
+ })
83
+ end
84
+
85
+ builders << {
86
+ :command => command,
87
+ :builder => builder,
88
+ :array => array,
89
+ :name => name,
90
+ :iterates => iterates
91
+ }
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,23 @@
1
+ module Conglomerate
2
+ module QueryBuilder
3
+ include Conglomerate::ParticleBuilder
4
+
5
+ builds Conglomerate::Query
6
+
7
+ module BuildOverride
8
+ def build(attrs = {})
9
+ instance_variable_set("@objects", nil)
10
+ super(attrs.merge({
11
+ :rel => _builder_name
12
+ }))
13
+ end
14
+ end
15
+
16
+ value :href
17
+ value :rel
18
+ value :name
19
+ value :prompt
20
+
21
+ builder :datum, Conglomerate::DatumBuilder, :name => :data, :array => true
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ module Conglomerate
2
+ module RootBuilder
3
+ include Conglomerate::ParticleBuilder
4
+
5
+ builds Conglomerate::Root
6
+
7
+ builder :collection, Conglomerate::CollectionBuilder
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ module Conglomerate
2
+ module TemplateBuilder
3
+ include Conglomerate::ParticleBuilder
4
+
5
+ builds Conglomerate::Template
6
+
7
+ module BuildOverride
8
+ def build(attrs = {})
9
+ instance_variable_set("@objects", nil)
10
+ super
11
+ end
12
+ end
13
+
14
+ builder :datum, Conglomerate::DatumBuilder, :name => :data, :array => true
15
+ end
16
+ end
@@ -9,10 +9,21 @@ module Conglomerate
9
9
  serialize_particle(item)
10
10
  elsif Conglomerate::Array === item
11
11
  serialize_array(item)
12
- elsif Array === item
12
+ elsif ::Array === item
13
13
  serialize_array(item)
14
14
  elsif item.is_a?(Numeric) || item.is_a?(String) || item.nil?
15
15
  item
16
+ elsif item.respond_to?(:to_s)
17
+ case item
18
+ when DateTime
19
+ item.to_time.utc.iso8601.sub(/\+00:00$/, "Z")
20
+ when Time
21
+ item.utc.iso8601.sub(/\+00:00$/, "Z")
22
+ when Date
23
+ item.strftime("%Y-%m-%d")
24
+ else
25
+ item
26
+ end
16
27
  end
17
28
  end
18
29
 
@@ -26,7 +37,7 @@ module Conglomerate
26
37
  attributes.inject({}) do |hash, (attr, attr_metadata)|
27
38
  hash.tap do |h|
28
39
  attribute = particle.send(attr)
29
- attribute ||= attr_metadata[:default]
40
+ attribute = attr_metadata[:default] if attribute == nil
30
41
 
31
42
  unless attr_metadata[:cull] && cull_attribute(attribute)
32
43
  h[attr.to_s] = serialize(attribute)
@@ -42,7 +53,7 @@ module Conglomerate
42
53
  end
43
54
 
44
55
  def cull_attribute(attribute)
45
- !attribute || (Conglomerate::Array === attribute && attribute.empty?)
56
+ (attribute == nil) || (Conglomerate::Array === attribute && attribute.empty?)
46
57
  end
47
58
  end
48
59
  end
@@ -1,3 +1,3 @@
1
1
  module Conglomerate
2
- VERSION = "0.10.0"
2
+ VERSION = "0.11.0"
3
3
  end
@@ -0,0 +1,56 @@
1
+ require_relative "spec_helper"
2
+ require_relative "../lib/conglomerate"
3
+ require_relative "../lib/conglomerate/ext/commands"
4
+
5
+ class CommandExtTestSerializer
6
+ include Conglomerate::RootBuilder.serializer
7
+
8
+ collection do
9
+ command :populate do
10
+ prompt { "test 123" }
11
+ href { populate_items_url }
12
+ datum :id
13
+ end
14
+ end
15
+ end
16
+
17
+ describe "Conglomerate Command Ext" do
18
+ let(:object) do
19
+ double(
20
+ "Object",
21
+ :id => 1
22
+ )
23
+ end
24
+
25
+ let(:context) do
26
+ double(
27
+ "Context",
28
+ :populate_items_url => "https://example.com/items/populate"
29
+ )
30
+ end
31
+
32
+ let(:test_serializer) do
33
+ CommandExtTestSerializer.new(object, :context => context).serialize
34
+ end
35
+
36
+ let(:test_collection) do
37
+ test_serializer["collection"]
38
+ end
39
+
40
+ context "#command" do
41
+ it "adds a command template to the collection" do
42
+ expect(test_collection["commands"]).to match_array(
43
+ [
44
+ {
45
+ "href" => "https://example.com/items/populate",
46
+ "rel" => "populate",
47
+ "prompt" => "test 123",
48
+ "data" => [
49
+ {"name" => "id", "value" => nil}
50
+ ]
51
+ }
52
+ ]
53
+ )
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,249 @@
1
+ require_relative "spec_helper"
2
+ require_relative "../lib/conglomerate"
3
+
4
+ class ConglomerateTestParticleSerializer
5
+ include Conglomerate::RootBuilder.serializer
6
+
7
+ collection do
8
+ href { test_url }
9
+
10
+ item "RSpec::Mocks::Double" do |item|
11
+ href { item_url(item.id) }
12
+
13
+ datum :description, :prompt => "awesome"
14
+ datum :id
15
+ datum :event_id
16
+ datum :roster_id
17
+ datum :team_ids
18
+
19
+ datum :event_date_time
20
+ datum :event_date
21
+ datum :event_time
22
+
23
+ datum :is_available
24
+
25
+ link :event, :href => Proc.new{ event_url(item.event_id) }
26
+ link :roster, :href => Proc.new{ roster_url(item.roster_id) }, :if => Proc.new{ item.roster_id }
27
+ link :teams, :href => Proc.new{ team_url(item.team_ids.join(",")) }
28
+ link :users, :href => Proc.new{ users_search_url(:object_id => item.id) }
29
+ end
30
+
31
+ link :events, :href => Proc.new { events_url }
32
+ query :search, :href => Proc.new { search_items_url } do
33
+ datum :id
34
+ end
35
+
36
+ template do
37
+ datum :repeats, :prompt => "true|false"
38
+ datum :description, :prompt => "awesome"
39
+ end
40
+ end
41
+ end
42
+
43
+ class ConglomerateExtraTestParticleSerializer
44
+ include Conglomerate::RootBuilder.serializer
45
+
46
+ collection do
47
+ item do
48
+ datum :id
49
+ end
50
+ end
51
+ end
52
+
53
+ class ConglomerateNullParticleSerializer
54
+ include Conglomerate::RootBuilder.serializer
55
+
56
+ collection do
57
+ end
58
+ end
59
+
60
+ describe Conglomerate do
61
+ let(:object) do
62
+ double(
63
+ "Object",
64
+ :id => 1,
65
+ :description => "Tasty Burgers",
66
+ :event_date_time => DateTime.parse("1981-11-28T10:00:00+00:00"),
67
+ :event_date => Date.parse("1981-11-28"),
68
+ :event_time => Time.parse("1981-11-28T10:00:00+00:00"),
69
+ :event_id => 2,
70
+ :roster_id => nil,
71
+ :team_ids => [1,2],
72
+ :user_ids => [],
73
+ :is_available => false
74
+ )
75
+ end
76
+
77
+ let(:context) do
78
+ request = double("Request", :original_url => "https://example.com/items")
79
+ double(
80
+ "Context",
81
+ :request => request,
82
+ :search_items_url => "https://example.com/items/search",
83
+ :populate_items_url => "https://example.com/items/populate",
84
+ ).tap do |context|
85
+ allow(context).to receive(:item_url).with(1) {
86
+ "https://example.com/items/1"
87
+ }
88
+ allow(context).to receive(:event_url).with(2) {
89
+ "https://example.com/events/2"
90
+ }
91
+ allow(context).to receive(:events_url) {
92
+ "https://example.com/events"
93
+ }
94
+ allow(context).to receive(:team_url).with("1,2") {
95
+ "https://example.com/teams/1,2"
96
+ }
97
+ allow(context).to receive(:test_url) { "abc" }
98
+ allow(context).to receive(:users_search_url).with(:object_id => 1) {
99
+ "def"
100
+ }
101
+ end
102
+ end
103
+
104
+ let(:test_serializer) do
105
+ ConglomerateTestParticleSerializer.new(object, :context => context).serialize
106
+ end
107
+
108
+ let(:extra_test_serializer) do
109
+ ConglomerateExtraTestParticleSerializer.new(object, :context => context).serialize
110
+ end
111
+
112
+ let(:null_serializer) do
113
+ ConglomerateNullParticleSerializer.new(object, :context => context).serialize
114
+ end
115
+
116
+ let(:test_collection) { test_serializer["collection"] }
117
+
118
+ let(:extra_test_collection) { extra_test_serializer["collection"] }
119
+
120
+ let(:null_collection) { null_serializer["collection"] }
121
+
122
+ describe "#version" do
123
+ it "sets version to 1.0" do
124
+ expect(null_collection["version"]).to eq("1.0")
125
+ expect(test_collection["version"]).to eq("1.0")
126
+ end
127
+ end
128
+
129
+ describe "#href" do
130
+ it "in context, uses the block to set the collection href" do
131
+ expect(test_collection["href"]).to eq("abc")
132
+ end
133
+
134
+ it "isn't included if the href is nil" do
135
+ expect(null_collection["href"]).to be_nil
136
+ end
137
+ end
138
+
139
+ describe "#query" do
140
+ it "doesn't include any query templates if none are provided" do
141
+ expect(null_collection.keys).to_not include("queries")
142
+ end
143
+
144
+ it "adds a query template to the collection" do
145
+ expect(test_collection["queries"]).to match_array(
146
+ [
147
+ {
148
+ "href" => "https://example.com/items/search",
149
+ "rel" => "search",
150
+ "data" => [
151
+ {"name" => "id", "value" => nil}
152
+ ]
153
+ }
154
+ ]
155
+ )
156
+ end
157
+ end
158
+
159
+ describe "#attribute(s)" do
160
+ context "items" do
161
+ it "skips items if there are no attributes" do
162
+ expect(null_collection.keys).to_not include("items")
163
+ end
164
+
165
+ it "doesn't have an items array if items is empty" do
166
+ test_serializer = ConglomerateTestParticleSerializer
167
+ .new(nil, :context => context)
168
+ .serialize
169
+ test_collection = test_serializer["collection"]
170
+ expect(test_collection.keys).to_not include("items")
171
+ end
172
+
173
+ it "includes an items array if attributes and objects present" do
174
+ expect(test_collection["items"]).to eq(
175
+ [
176
+ {
177
+ "href" => "https://example.com/items/1",
178
+ "data" => [
179
+ {"name" => "description", "value" => "Tasty Burgers", "prompt" => "awesome"},
180
+ {"name" => "id", "value" => 1},
181
+ {"name" => "event_id", "value" => 2},
182
+ {"name" => "roster_id", "value" => nil},
183
+ {"name" => "team_ids", "value" => [1,2]},
184
+ {"name" => "event_date_time", "value" => "1981-11-28T10:00:00Z"},
185
+ {"name" => "event_date", "value" => "1981-11-28"},
186
+ {"name" => "event_time", "value" => "1981-11-28T10:00:00Z"},
187
+ {"name" => "is_available", "value" => false}
188
+ ],
189
+ "links" => [
190
+ {"rel" => "event", "href" => "https://example.com/events/2"},
191
+ {"rel" => "teams", "href" => "https://example.com/teams/1,2"},
192
+ {"rel" => "users", "href" => "def"}
193
+ ]
194
+ }
195
+ ]
196
+ )
197
+ end
198
+
199
+ it "doesn't include links if there are none" do
200
+ expect(extra_test_collection["items"]).to eq(
201
+ [
202
+ {
203
+ "data" => [
204
+ {"name" => "id", "value" => 1}
205
+ ]
206
+ }
207
+ ]
208
+ )
209
+ end
210
+ end
211
+
212
+ context "template" do
213
+ it "skips template if there are no attributes for a template" do
214
+ expect(null_collection.keys).to_not include("template")
215
+ end
216
+
217
+ it "includes a valid template if attributes have them" do
218
+ expect(test_collection["template"]["data"]).to match_array(
219
+ [
220
+ {"name" => "description", "value" => nil, "prompt" => "awesome"},
221
+ {"name" => "repeats", "value" => nil, "prompt" => "true|false"}
222
+ ]
223
+ )
224
+ end
225
+ end
226
+ end
227
+
228
+ describe "#link" do
229
+ it "skips links if there are none present" do
230
+ expect(null_collection.keys).to_not include("links")
231
+ end
232
+
233
+ it "adds links if they are present" do
234
+ expect(test_collection["links"]).to match_array(
235
+ [
236
+ {"rel" => "events", "href" => "https://example.com/events"}
237
+ ]
238
+ )
239
+ end
240
+ end
241
+
242
+ describe "#item_link" do
243
+ it "adds links if they are present" do
244
+ expect(test_collection["items"][0]["links"]).to include(
245
+ {"rel" => "teams", "href" => "https://example.com/teams/1,2"}
246
+ )
247
+ end
248
+ end
249
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: conglomerate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Emmons
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-06-03 00:00:00.000000000 Z
12
+ date: 2014-06-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -68,25 +68,39 @@ files:
68
68
  - conglomerate.gemspec
69
69
  - lib/conglomerate.rb
70
70
  - lib/conglomerate/array.rb
71
+ - lib/conglomerate/builder_call.rb
72
+ - lib/conglomerate/builder_serializer.rb
71
73
  - lib/conglomerate/collection.rb
74
+ - lib/conglomerate/collection_builder.rb
72
75
  - lib/conglomerate/command.rb
73
76
  - lib/conglomerate/datum.rb
77
+ - lib/conglomerate/datum_builder.rb
74
78
  - lib/conglomerate/error.rb
79
+ - lib/conglomerate/ext/commands.rb
75
80
  - lib/conglomerate/item.rb
81
+ - lib/conglomerate/item_builder.rb
76
82
  - lib/conglomerate/link.rb
83
+ - lib/conglomerate/link_builder.rb
84
+ - lib/conglomerate/mixin_ivar_helper.rb
77
85
  - lib/conglomerate/particle.rb
86
+ - lib/conglomerate/particle_builder.rb
78
87
  - lib/conglomerate/query.rb
88
+ - lib/conglomerate/query_builder.rb
79
89
  - lib/conglomerate/root.rb
90
+ - lib/conglomerate/root_builder.rb
80
91
  - lib/conglomerate/serializer.rb
81
92
  - lib/conglomerate/template.rb
93
+ - lib/conglomerate/template_builder.rb
82
94
  - lib/conglomerate/tree_deserializer.rb
83
95
  - lib/conglomerate/tree_serializer.rb
84
96
  - lib/conglomerate/version.rb
85
97
  - spec/collection_spec.rb
98
+ - spec/command_ext_spec.rb
86
99
  - spec/command_spec.rb
87
100
  - spec/conglomerate_spec.rb
88
101
  - spec/datum_spec.rb
89
102
  - spec/link_spec.rb
103
+ - spec/particle_builder_spec.rb
90
104
  - spec/particle_spec.rb
91
105
  - spec/query_spec.rb
92
106
  - spec/spec_helper.rb
@@ -117,10 +131,12 @@ specification_version: 4
117
131
  summary: A library to serialize Ruby objects into collection+json
118
132
  test_files:
119
133
  - spec/collection_spec.rb
134
+ - spec/command_ext_spec.rb
120
135
  - spec/command_spec.rb
121
136
  - spec/conglomerate_spec.rb
122
137
  - spec/datum_spec.rb
123
138
  - spec/link_spec.rb
139
+ - spec/particle_builder_spec.rb
124
140
  - spec/particle_spec.rb
125
141
  - spec/query_spec.rb
126
142
  - spec/spec_helper.rb