conglomerate 0.10.0 → 0.11.0

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