conglomerate 0.7.0 → 0.8.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: 9ecec2dd728808b6548bbd891a90a1ae6939afa1
4
- data.tar.gz: a109f0656695f3abbfa1d99e4c71055cfc434c59
3
+ metadata.gz: f9f3f14b27e132968770842dd2d3fe7796a25fbc
4
+ data.tar.gz: 2174933a1f8470094242bbb92f77f967aaaa0dfc
5
5
  SHA512:
6
- metadata.gz: 0e2f0834e369486e5d9e8d16d99d3d9683736b62a195713155b5dde44101ef0375ae59405d81cec6562f1ce3a39cc6fb108e239912a2b37a75ced1b76dafeae6
7
- data.tar.gz: 466427fff930ebd97cbe510116ba80ad5075be0d15b2387c21e69475e0455b21bf26fcd6201c605533e705f6c7386d92c532e78d860edc4237fbff3e90c01a7e
6
+ metadata.gz: 080da2cec601bb44e310a6afad4dad3560bd47aa56f2de7feb0f9aef7ced1049fe5547d15028965583fe47e66486c42f9ad909458e7743ca0449635bfd211770
7
+ data.tar.gz: f5b2ea4b96a812f0f54d5b12a0f5bf5212d8af9d8441d4d8397bfe6586a63f8bfd7594eb21a0ed8236fb1fcaff88fe62b83813ce29b6a2e16b0fa9099e430218
data/.gitignore CHANGED
@@ -8,6 +8,7 @@ InstalledFiles
8
8
  _yardoc
9
9
  coverage
10
10
  doc/
11
+ bin/
11
12
  lib/bundler/man
12
13
  pkg
13
14
  rdoc
data/conglomerate.gemspec CHANGED
@@ -6,7 +6,7 @@ require "conglomerate/version"
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "conglomerate"
8
8
  spec.version = Conglomerate::VERSION
9
- spec.authors = ["Shane Emmons"]
9
+ spec.authors = ["Shane Emmons", "Emily Dobervich"]
10
10
  spec.email = ["oss@teamsnap.com"]
11
11
  spec.summary = "A library to serialize Ruby objects into collection+json"
12
12
  spec.description = "A library to serialize Ruby objects into collection+json"
@@ -0,0 +1,30 @@
1
+ module Conglomerate
2
+ class Array
3
+ include Enumerable
4
+
5
+ def initialize(type)
6
+ self.type = type
7
+ self.storage = []
8
+ end
9
+
10
+ def <<(val)
11
+ if type
12
+ raise "TypeMismatch" unless val.is_a?(type)
13
+ end
14
+
15
+ storage << val
16
+ end
17
+
18
+ def empty?
19
+ storage.empty?
20
+ end
21
+
22
+ def each(&block)
23
+ storage.each(&block)
24
+ end
25
+
26
+ private
27
+
28
+ attr_accessor :storage, :type
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ module Conglomerate
2
+ class Collection
3
+ include Particle
4
+
5
+ attribute :version, :default => "1.0"
6
+ attribute :href
7
+
8
+ attribute :template, :type => Template
9
+ attribute :error, :type => Error
10
+
11
+ array :items, :contains => Item
12
+ array :links, :contains => Link
13
+ array :queries, :contains => Query
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module Conglomerate
2
+ class Datum
3
+ include Conglomerate::Particle
4
+
5
+ attribute :name, :type => String, :required => true
6
+ attribute :value
7
+ attribute :prompt, :type => String
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Conglomerate
2
+ class Error
3
+ include Conglomerate::Particle
4
+
5
+ attribute :title, :type => String
6
+ attribute :code, :type => String
7
+ attribute :message, :type => String
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ module Conglomerate
2
+ class Item
3
+ include Conglomerate::Particle
4
+
5
+ attribute :href, :type => String
6
+
7
+ array :data, :contains => Datum
8
+ array :links, :contains => Link
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module Conglomerate
2
+ class Link
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 :render, :type => String
9
+ attribute :prompt, :type => String
10
+ end
11
+ end
@@ -0,0 +1,73 @@
1
+ module Conglomerate
2
+ module Particle
3
+ def self.included(object)
4
+ object.send(:extend, ClassMethods)
5
+ end
6
+
7
+ def initialize(attributes = {})
8
+ self.class.attributes.each do |attr, attr_metadata|
9
+ if attr_metadata[:required]
10
+ raise "MissingAttribute" unless attributes[attr] || attributes[attr.to_s]
11
+ end
12
+
13
+ if attr_metadata[:type] == :array
14
+ self.instance_variable_set("@#{attr}", Conglomerate::Array.new(attr_metadata[:contains]))
15
+ end
16
+ end
17
+
18
+ attributes.each do |key, value|
19
+ attrs = self.class.attributes
20
+ if attrs[key.to_sym] && attrs[key.to_sym][:type] == :array
21
+ array = value
22
+ value = Conglomerate::Array.new(attrs[key.to_sym][:contains])
23
+ array.each { |item| value << item }
24
+ self.instance_variable_set("@#{key}", value)
25
+ end
26
+
27
+ self.send("#{key}=", value) if self.respond_to?("#{key}=")
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ module ClassMethods
34
+ def self.extended(klass)
35
+ klass.instance_variable_set("@attributes", {})
36
+ end
37
+
38
+ def attributes
39
+ instance_variable_get("@attributes").dup
40
+ end
41
+
42
+ private
43
+
44
+ def array(attr, contains: nil, cull: true)
45
+ attribute(attr, :type => :array, :contains => contains, :cull => cull)
46
+ end
47
+
48
+ def attribute(attr, default: nil, type: nil, contains: nil, cull: true, required: nil)
49
+ instance_variable_get("@attributes")[attr] = {
50
+ :default => default,
51
+ :type => type,
52
+ :contains => contains,
53
+ :cull => cull,
54
+ :required => required
55
+ }
56
+
57
+ self.send(:attr_reader, attr)
58
+
59
+ if type != :array
60
+ self.send(:define_method, :"#{attr}=") do |val|
61
+ attr_metadata = self.class.attributes[attr]
62
+
63
+ if type = attr_metadata[:type]
64
+ raise "TypeMismatch" if !val.is_a?(type)
65
+ end
66
+
67
+ self.instance_variable_set("@#{attr}", val)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,12 @@
1
+ module Conglomerate
2
+ class Query
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
+ end
@@ -0,0 +1,6 @@
1
+ module Conglomerate
2
+ class Root
3
+ include Particle
4
+ attribute :collection
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ module Conglomerate
2
+ class Template
3
+ include Conglomerate::Particle
4
+
5
+ array :data, :contains => Datum
6
+ end
7
+ end
@@ -0,0 +1,53 @@
1
+ module Conglomerate
2
+ class TreeDeserializer
3
+ PARTICLES = [Collection, Item, Error, Template, Datum, Query, Item]
4
+
5
+ def initialize(object)
6
+ self.object = object
7
+ end
8
+
9
+ def deserialize(item = object)
10
+ raise "ObjectNotCollectionRoot" if !object["collection"]
11
+ deserialize_particle(object["collection"], Collection)
12
+ end
13
+
14
+ private
15
+
16
+ attr_accessor :object
17
+
18
+ def deserialize_particle(object, klass)
19
+ attributes = {}
20
+ attribute_info = klass.attributes
21
+
22
+ attribute_info.each do |attr, attr_metadata|
23
+ attr = attr.to_s
24
+ if object[attr]
25
+ attributes[attr] = deserialize_attribute(object[attr], attr_metadata)
26
+ end
27
+ end
28
+
29
+ particle = klass.new(attributes)
30
+ end
31
+
32
+ def deserialize_attribute(attribute, attr_metadata)
33
+ if PARTICLES.include?(attr_metadata[:type])
34
+ deserialize_particle(attribute, attr_metadata[:type])
35
+ elsif attr_metadata[:type] == :array
36
+ raise "ArrayExpected" unless attribute.is_a?(::Array)
37
+ deserialize_array(attribute, attr_metadata[:contains])
38
+ else
39
+ attribute
40
+ end
41
+ end
42
+
43
+ def deserialize_array(items, contains)
44
+ array = Conglomerate::Array.new(contains)
45
+
46
+ items.each do |item|
47
+ array << deserialize_particle(item, contains)
48
+ end
49
+
50
+ array
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,48 @@
1
+ module Conglomerate
2
+ class TreeSerializer
3
+ def initialize(object)
4
+ self.object = object
5
+ end
6
+
7
+ def serialize(item = object)
8
+ if Conglomerate::Particle === item
9
+ serialize_particle(item)
10
+ elsif Conglomerate::Array === item
11
+ serialize_array(item)
12
+ elsif Array === item
13
+ serialize_array(item)
14
+ elsif item.is_a?(Numeric) || item.is_a?(String) || item.nil?
15
+ item
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ attr_accessor :object
22
+
23
+ def serialize_particle(particle)
24
+ attributes = particle.class.attributes
25
+
26
+ attributes.inject({}) do |hash, (attr, attr_metadata)|
27
+ hash.tap do |h|
28
+ attribute = particle.send(attr)
29
+ attribute ||= attr_metadata[:default]
30
+
31
+ unless attr_metadata[:cull] && cull_attribute(attribute)
32
+ h[attr.to_s] = serialize(attribute)
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def serialize_array(array)
39
+ array.map do |item|
40
+ serialize(item)
41
+ end
42
+ end
43
+
44
+ def cull_attribute(attribute)
45
+ !attribute || (Conglomerate::Array === attribute && attribute.empty?)
46
+ end
47
+ end
48
+ end
@@ -1,3 +1,3 @@
1
1
  module Conglomerate
2
- VERSION = "0.7.0"
2
+ VERSION = "0.8.0"
3
3
  end
data/lib/conglomerate.rb CHANGED
@@ -1,6 +1,21 @@
1
+ require_relative "conglomerate/tree_serializer"
2
+ require_relative "conglomerate/array"
3
+ require_relative "conglomerate/particle"
1
4
  require_relative "conglomerate/serializer"
5
+ require_relative "conglomerate/link"
6
+ require_relative "conglomerate/error"
7
+ require_relative "conglomerate/datum"
8
+ require_relative "conglomerate/template"
9
+ require_relative "conglomerate/item"
10
+ require_relative "conglomerate/query"
11
+ require_relative "conglomerate/collection"
12
+ require_relative "conglomerate/tree_deserializer"
2
13
 
3
14
  module Conglomerate
15
+ def self.serialize(serializable)
16
+ Conglomerate::TreeSerializer.new(serializable).serialize
17
+ end
18
+
4
19
  def self.serializer
5
20
  Module.new do
6
21
  def self.included(descendant)
@@ -0,0 +1,40 @@
1
+ require_relative "spec_helper"
2
+ require_relative "../lib/conglomerate"
3
+
4
+ describe Conglomerate::Collection do
5
+ let(:collection) { Conglomerate::Collection.new }
6
+ subject(:serialized_empty_collection) { Conglomerate.serialize(collection) }
7
+ subject(:reference_empty_collection) {
8
+ {
9
+ "version" => "1.0"
10
+ }
11
+ }
12
+
13
+ it "empty collection serializes properly" do
14
+ expect(serialized_empty_collection).to eq(reference_empty_collection)
15
+ end
16
+
17
+ context "links" do
18
+ it "serializes links correctly" do
19
+ link = Conglomerate::Link.new(
20
+ :href => "http://this.is.a.link",
21
+ :rel => "Something"
22
+ )
23
+
24
+ collection.links << link
25
+ expect(Conglomerate.serialize(collection)["links"]).to include(Conglomerate.serialize(link))
26
+ end
27
+ end
28
+
29
+ context "queries" do
30
+ it "serializes queries correctly" do
31
+ query = Conglomerate::Query.new(
32
+ :href => "http://this.is.a.query",
33
+ :rel => "Something"
34
+ )
35
+
36
+ collection.queries << query
37
+ expect(Conglomerate.serialize(collection)["queries"]).to include(Conglomerate.serialize(query))
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ require_relative "spec_helper"
2
+ require_relative "../lib/conglomerate"
3
+
4
+ describe Conglomerate::Datum do
5
+ context "required attributes" do
6
+ specify "name" do
7
+ expect { Conglomerate::Datum.new }.to raise_error("MissingAttribute")
8
+ end
9
+ end
10
+
11
+ context "optional attributes" do
12
+ specify "value" do
13
+ datum = Conglomerate::Datum.new(:name => "name")
14
+ expect(datum).to respond_to(:"value=")
15
+ end
16
+
17
+ specify "prompt" do
18
+ datum = Conglomerate::Datum.new(:name => "name")
19
+ expect(datum).to respond_to(:"prompt=")
20
+ expect { datum.prompt = 3 }.to raise_error
21
+ end
22
+ end
23
+ end
data/spec/link_spec.rb ADDED
@@ -0,0 +1,14 @@
1
+ require_relative "spec_helper"
2
+ require_relative "../lib/conglomerate"
3
+
4
+ describe Conglomerate::Link do
5
+ context "required attributes" do
6
+ specify "href" do
7
+ expect { Conglomerate::Link.new(:rel => "") }.to raise_error("MissingAttribute")
8
+ end
9
+
10
+ specify "rel" do
11
+ expect { Conglomerate::Link.new(:href => "") }.to raise_error("MissingAttribute")
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ require_relative "spec_helper"
2
+ require_relative "../lib/conglomerate"
3
+
4
+ class ParticleTest
5
+ include Conglomerate::Particle
6
+
7
+ attribute :default, :default => "this is the default value"
8
+ attribute :string, :type => String
9
+ end
10
+
11
+ describe Conglomerate::Particle do
12
+ subject(:serialized_particle_test) { Conglomerate.serialize(ParticleTest.new) }
13
+ subject(:mass_assigned) { ParticleTest.new(:string => "An string", :default => "Not an default") }
14
+
15
+ it "default values are exposed when serialized" do
16
+ expect(serialized_particle_test["default"]).to eq("this is the default value")
17
+ end
18
+
19
+ it "enforces type on attributes" do
20
+ particle_test = ParticleTest.new
21
+ expect {
22
+ particle_test.string = 1
23
+ }.to raise_error("TypeMismatch")
24
+ end
25
+
26
+ it "allows mass-assignment via constructor" do
27
+ expect(mass_assigned.string).to eq("An string")
28
+ expect(mass_assigned.default).to eq("Not an default")
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ require_relative "spec_helper"
2
+ require_relative "../lib/conglomerate"
3
+
4
+ describe Conglomerate::Query do
5
+ let(:query) {
6
+ Conglomerate::Query.new(
7
+ :href => "http://this.is.a.query/",
8
+ :rel => "some_query"
9
+ )
10
+ }
11
+
12
+ context "required attributes" do
13
+ specify "href" do
14
+ expect { Conglomerate::Query.new(:rel => "") }.to raise_error("MissingAttribute")
15
+ end
16
+
17
+ specify "rel" do
18
+ expect { Conglomerate::Query.new(:href => "") }.to raise_error("MissingAttribute")
19
+ end
20
+ end
21
+
22
+ context "data" do
23
+ it "serializes properly" do
24
+ datum = Conglomerate::Datum.new(:name => "name")
25
+
26
+ query.data << datum
27
+ expect(Conglomerate.serialize(query)["data"]).to include(Conglomerate.serialize(datum))
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,38 @@
1
+ require_relative "spec_helper"
2
+ require_relative "../lib/conglomerate"
3
+
4
+ require "json"
5
+
6
+ describe Conglomerate::TreeDeserializer do
7
+ it "deserializes collection with error" do
8
+ json = '{"collection":{"version":"1.0","href":"https://apiv3.teamsnap.com/","links":[{"rel":"root","href":"https://apiv3.teamsnap.com/"},{"rel":"self","href":"https://apiv3.teamsnap.com/"}],"error":{"message":"translation missing: en.errors.messages.unauthorized"}}}'
9
+ obj = JSON.parse(json)
10
+ deserializer = Conglomerate::TreeDeserializer.new(obj)
11
+ tree = deserializer.deserialize
12
+
13
+ expect(tree.class).to eq(Conglomerate::Collection)
14
+ expect(tree.error.class).to eq(Conglomerate::Error)
15
+ expect(tree.href).to eq("https://apiv3.teamsnap.com/")
16
+ end
17
+
18
+ it "deserializes collection with items" do
19
+ obj = {
20
+ "collection" => {
21
+ "version" => "1.0",
22
+ "href" => "http://example.com/",
23
+ "items" => [
24
+ { "href" => "http://example.com/1", "data" => [{
25
+ "name" => "is_unicorn", "value" => true
26
+ }]}
27
+ ]
28
+ }
29
+ }
30
+
31
+ deserializer = Conglomerate::TreeDeserializer.new(obj)
32
+ tree = deserializer.deserialize
33
+
34
+ expect(
35
+ tree.items.first.data.find { |datum| datum.name == "is_unicorn" }.value
36
+ ).to eq(true)
37
+ end
38
+ end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: conglomerate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Emmons
8
+ - Emily Dobervich
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-04-18 00:00:00.000000000 Z
12
+ date: 2014-05-13 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
@@ -66,10 +67,28 @@ files:
66
67
  - Rakefile
67
68
  - conglomerate.gemspec
68
69
  - lib/conglomerate.rb
70
+ - lib/conglomerate/array.rb
71
+ - lib/conglomerate/collection.rb
72
+ - lib/conglomerate/datum.rb
73
+ - lib/conglomerate/error.rb
74
+ - lib/conglomerate/item.rb
75
+ - lib/conglomerate/link.rb
76
+ - lib/conglomerate/particle.rb
77
+ - lib/conglomerate/query.rb
78
+ - lib/conglomerate/root.rb
69
79
  - lib/conglomerate/serializer.rb
80
+ - lib/conglomerate/template.rb
81
+ - lib/conglomerate/tree_deserializer.rb
82
+ - lib/conglomerate/tree_serializer.rb
70
83
  - lib/conglomerate/version.rb
84
+ - spec/collection_spec.rb
71
85
  - spec/conglomerate_spec.rb
86
+ - spec/datum_spec.rb
87
+ - spec/link_spec.rb
88
+ - spec/particle_spec.rb
89
+ - spec/query_spec.rb
72
90
  - spec/spec_helper.rb
91
+ - spec/tree_deserializer_spec.rb
73
92
  homepage: https://github.com/teamsnap/conglomerate
74
93
  licenses:
75
94
  - MIT
@@ -95,5 +114,11 @@ signing_key:
95
114
  specification_version: 4
96
115
  summary: A library to serialize Ruby objects into collection+json
97
116
  test_files:
117
+ - spec/collection_spec.rb
98
118
  - spec/conglomerate_spec.rb
119
+ - spec/datum_spec.rb
120
+ - spec/link_spec.rb
121
+ - spec/particle_spec.rb
122
+ - spec/query_spec.rb
99
123
  - spec/spec_helper.rb
124
+ - spec/tree_deserializer_spec.rb