cot 0.1.3 → 0.2.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: 8718cf838c838590a4c3c8fa565d136d3de861b9
4
- data.tar.gz: 875186e08f60fe759f77ddeab1b0f50aa6ba3a25
3
+ metadata.gz: b47b0825bf582a0dded1ff4736bef69945d6f485
4
+ data.tar.gz: f10875feef7630460c617c154dd6564bb1eb210a
5
5
  SHA512:
6
- metadata.gz: e08b26c691f494eaff718912b694c13fd92a850bf928f3f67ede2510cbc5a16b63522c6e06318ad8f3ff256a439b25639cb92b73016348287b79697b992083d4
7
- data.tar.gz: bd6f6bdcda4fd1499b936fe93c79fcdde2e8353cebcafa8872f21bb3e3956fb325f7fa74560e1314187b7d9eddf03e37192ccd411c4e38fd08dffc544a96a148
6
+ metadata.gz: b1c6d69f790c266a5e73a29d4ed74dbb491d0f2111a3f1224c03abcc87e4520822ebd094e8a6979a77ede993cfb64a5e78187ce1a506468c5c8a62e0ba5f20e2
7
+ data.tar.gz: 155a93d43a4b96ed4f71d3e4e08653c251b4235ba4d35f53d61396327136e103b3a8972b66e809bd96a9896764f29bbe24d52e85e2275412a36b5c42fcb696b7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cot (0.1.2)
4
+ cot (0.2.0)
5
5
  activemodel
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -5,12 +5,13 @@ Cot is a gem designed to help convert rest based resources into ruby objects. C
5
5
 
6
6
  ### Usage
7
7
 
8
- Using cot is pretty simple, include it in your project and then have your class inherit from Cot::Frame.
8
+ Using cot is pretty simple. There are two main classes: Collection and Frame. Collections are basically big arrays that contain objects (presumably Frame objects). Collection provides some helper methods to manage the collection, but also delegates to Array, so each, map and all that good stuff are there as well. Frame allows you to declare how the object will convert a json payload into an object.
9
9
 
10
10
  Frame provides some helpful methods:
11
11
  - Class Methods
12
12
  - property adds the first parameter as an accessor on the object. There are two optional arguments, from and searchable. From indicates that the property has an alternate key in the incoming/outgoing data. Searchable adds the property to the search mappings.
13
13
  - search\_property adds the parameter to the search mapping. It takes an optional from argument which inidates the property has an alternate key in the incoming/outgoing data.
14
+ - enum *NOT SUPPORTED* If you'd like to see this let me know. Also let me know what you'd want it to look like.
14
15
  - Instance Methods
15
16
  - defined\_properties returns a list of the defined properties
16
17
  - properties\_mapping returns a hash containing all of the renamed properties. The keys are the values of the from argument and the values are the property name.
@@ -19,6 +20,18 @@ Frame provides some helpful methods:
19
20
  - inverted\_search\_mappings returns an inverted search\_mappings hash.
20
21
  - serializable\_hash returns hash with the correct keys to post back. AKA, it reverts the keys to what the from arguments (if any) were.
21
22
  - to\_json returns a json encoded version of serializable\_hash.
23
+ - valid? true if errors is empty
24
+ - errors used to store any errors associated with the object
25
+
26
+ Collection provides the following methods:
27
+ - Instance Methods
28
+ - The following methods collate the results from members
29
+ - serializable\_hash
30
+ - to\_json
31
+ - errors (pulls into a hash with member.id as the key)
32
+ - exists? returns true if *all* the members exist
33
+ - changed? returns true if *any* of the members have changed
34
+ - update\_members updates the members of the collection to based on the payload (this can add or remove members)
22
35
 
23
36
  ```ruby
24
37
  class ExampleObject < Cot::Frame
@@ -28,9 +41,21 @@ class ExampleObject < Cot::Frame
28
41
  search_property :created_at, :from => :createdOn
29
42
  end
30
43
 
44
+ class ExampleCollection < Cot::Collection
45
+ def initialize(params)
46
+ super ExampleObject, params
47
+ end
48
+ end
49
+
31
50
  thingy = ExampleObject.new(id: :my_id, name: 'awesome name', createdOn: Time.now)
32
51
  thingy.id # 5
33
52
  thingy.name # awesome name
34
53
  thingy.created_at # what time it is now
35
54
  thingy.defined\_properties # [:id, :name, :created_at]
55
+
56
+ collection = ExampleCollection.new [{ id: :my_id, name: 'awesome name', createdOn: Time.now }, { id: :my_id, name: 'awesome name', createdOn: Time.now }]
57
+ collection.first.name # 'awesome name'
58
+ collection.exists? # Do all of the entries exist?
59
+ collection.update_members [{ id: 1, name: 'new awesome name', createdOn: Time.now }, { id: 2, name: 'new awesome name', createdOn: Time.now }]
60
+ collection.first.name # 'new awesome name'
36
61
  ```
data/lib/cot.rb CHANGED
@@ -2,10 +2,8 @@ require 'active_model'
2
2
 
3
3
  require 'cot/version'
4
4
  require 'cot/frame'
5
+ require 'cot/collection'
5
6
  require 'json'
6
7
 
7
8
  module Cot
8
- def version_string
9
- "Cot version #{Cot::VERSION}"
10
- end
11
9
  end
@@ -0,0 +1,55 @@
1
+ module Cot
2
+ class Collection < SimpleDelegator
3
+ def initialize(klass, objects, sub_key = false)
4
+ @klass = klass
5
+ @sub_key = sub_key
6
+ @objects = objects
7
+
8
+ # If you pass in different types of things here we can't be friends
9
+ initialize_objects(objects) unless objects.first.is_a? klass
10
+
11
+ super @objects
12
+ end
13
+
14
+ def serializable_hash
15
+ @objects.map(&:serializable_hash)
16
+ end
17
+
18
+ def to_json
19
+ serializable_hash.to_json
20
+ end
21
+
22
+ def exists?
23
+ @objects.map(&:exists?).all?
24
+ end
25
+
26
+ def errors
27
+ Hash[@objects.reject { |x| x.valid? }.map { |x| [x.id, x.errors] }]
28
+ end
29
+
30
+ def update_members(payload)
31
+ # NOTE: replacing objects is lazy, but I don't want to deal with updating and such right now
32
+ initialize_objects(payload)
33
+ end
34
+
35
+ def changed?
36
+ @objects.map(&:changed?).include? true
37
+ end
38
+
39
+ private
40
+
41
+ def initialize_objects(objects)
42
+ @objects = []
43
+ @objects = objects.map do |payload|
44
+ if @sub_key
45
+ @klass.new payload[@sub_key]
46
+ else
47
+ @klass.new payload
48
+ end
49
+ end
50
+
51
+ # Set the delegator methods to point to the new objects array
52
+ __setobj__(@objects)
53
+ end
54
+ end
55
+ end
data/lib/cot/frame.rb CHANGED
@@ -6,6 +6,7 @@ module Cot
6
6
  include ActiveModel::Dirty
7
7
 
8
8
  def initialize(payload = {})
9
+ @errors = {}
9
10
  @data = convert_keys payload
10
11
  end
11
12
 
@@ -68,6 +69,8 @@ module Cot
68
69
  define_attribute_method name
69
70
  end
70
71
 
72
+ attr_accessor :errors
73
+
71
74
  def [](key)
72
75
  @data[convert_key key]
73
76
  end
@@ -76,6 +79,10 @@ module Cot
76
79
  @data[convert_key key] = value
77
80
  end
78
81
 
82
+ def valid?
83
+ errors.empty?
84
+ end
85
+
79
86
  def to_json
80
87
  serializable_hash.to_json
81
88
  end
data/lib/cot/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Cot
2
- VERSION = '0.1.3'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -0,0 +1,120 @@
1
+ require 'spec_helper'
2
+ class FakeDouble < Cot::Frame
3
+ property :id
4
+ property :foo
5
+ property :fooy
6
+ end
7
+
8
+ describe Cot::Collection do
9
+ let(:obj1) { FakeDouble.new id: 1, foo: :bar }
10
+ let(:obj2) { FakeDouble.new id: 2, foo: :bar }
11
+ subject(:collection) { Cot::Collection.new FakeDouble, [obj1, obj2] }
12
+
13
+ context 'array like' do
14
+ it 'should take an array of objects and store them in a hash' do
15
+ expect(collection.length).to eq 2
16
+ end
17
+
18
+ it 'should respond to array methods' do
19
+
20
+ # In theory we'd test more, but that's good enough for me
21
+ expect(collection).to respond_to :[]
22
+ expect(collection).to respond_to :first
23
+ expect(collection).to respond_to :reverse
24
+ end
25
+ end
26
+
27
+ context 'serializable_hash' do
28
+ it 'is an array' do
29
+ expect(collection.serializable_hash).to be_kind_of Array
30
+ end
31
+
32
+ it 'has hash members' do
33
+ expect(collection.serializable_hash.first).to be_kind_of Hash
34
+ end
35
+ end
36
+
37
+ context 'to_json' do
38
+ it 'returns a string' do
39
+ expect(collection.to_json).to be_kind_of String
40
+ end
41
+
42
+ it 'is parseable json' do
43
+ expect(JSON.parse(collection.to_json)).to be_kind_of Array
44
+ end
45
+ end
46
+
47
+ context 'exists?' do
48
+ it 'returns true if all the objects exist' do
49
+ expect(obj1).to receive(:exists?).and_return true
50
+ expect(obj2).to receive(:exists?).and_return true
51
+ expect(collection.exists?).to be true
52
+ end
53
+
54
+ it 'returns false if any of the objects do not exist' do
55
+ expect(obj1).to receive(:exists?).and_return true
56
+ expect(obj2).to receive(:exists?).and_return false
57
+ expect(collection.exists?).to be false
58
+ end
59
+ end
60
+
61
+ context 'errors' do
62
+ it 'is empty if there are no errors' do
63
+ expect(collection.errors).to be_empty
64
+ end
65
+
66
+ it 'collates the errors of the contained objects' do
67
+ obj2.errors = { status: 400 }
68
+ expect(collection.errors.size).to be 1
69
+ expect(collection.errors[2]).to have_key :status
70
+ end
71
+ end
72
+
73
+ context 'initialize' do
74
+ it 'does not process the objects if they are already the correct class' do
75
+ coll = Cot::Collection.new FakeDouble, [FakeDouble.new(fooy: :bar), FakeDouble.new(asdf: :fdas)]
76
+ expect(coll.first).to be_kind_of FakeDouble
77
+ end
78
+
79
+ it 'creates new instances of the passed klass if the objects are not already the class' do
80
+ coll = Cot::Collection.new FakeDouble, [{ fooy: :bar }, { asdf: :fdas }]
81
+ expect(coll.first).to be_kind_of FakeDouble
82
+ end
83
+
84
+ it 'takes an optional sub_key to pull the object out of the payload' do
85
+ coll = Cot::Collection.new FakeDouble, [{ inner: { fooy: :bar } }, { inner: { asdf: :fdas } }], :inner
86
+ expect(coll.first).to be_kind_of FakeDouble
87
+ expect(coll.first.fooy).to eq :bar
88
+ end
89
+ end
90
+
91
+ context 'update members' do
92
+ it 'updates members' do
93
+ coll = Cot::Collection.new FakeDouble, [{ fooy: :bar }]
94
+ expect(coll.length).to eq 1
95
+ coll.update_members [{ id: 123, foo: :bar }]
96
+ expect(coll.first.id).to eq 123
97
+ end
98
+
99
+ it 'removes members that are not in the payload' do
100
+ coll = Cot::Collection.new FakeDouble, [{ fooy: :bar }, { asdf: :fdas }]
101
+ expect(coll.length).to eq 2
102
+ coll.update_members [{ id: 123, foo: :bar }]
103
+ expect(coll.first.id).to eq 123
104
+ expect(coll.length).to eq 1
105
+ end
106
+ end
107
+
108
+ context 'changed?' do
109
+ it 'returns true if one of the objects has changed' do
110
+ coll = Cot::Collection.new FakeDouble, [{ fooy: :bar }]
111
+ coll.first.fooy = 'baz'
112
+ expect(coll.changed?).to be true
113
+ end
114
+
115
+ it 'return false if none of the objects have changed' do
116
+ coll = Cot::Collection.new FakeDouble, [{ fooy: :bar }]
117
+ expect(coll.changed?).to be false
118
+ end
119
+ end
120
+ end
@@ -52,6 +52,7 @@ describe Cot::Frame do
52
52
  it 'is true if id is present' do
53
53
  expect(@foo.exists?).to be_truthy
54
54
  end
55
+
55
56
  it 'is false if id is not present' do
56
57
  foo = TestObject.new(foo: 5)
57
58
  expect(foo.exists?).to be_falsey
@@ -61,6 +62,7 @@ describe Cot::Frame do
61
62
  it 'includes foo' do
62
63
  expect(@foo.defined_properties).to include :foo
63
64
  end
65
+
64
66
  it 'is an array' do
65
67
  expect(@foo.defined_properties).to be_kind_of Array
66
68
  end
@@ -100,6 +102,7 @@ describe Cot::Frame do
100
102
  expect(TestObject.mappings).to have_key :bar
101
103
  expect(TestObject.mappings[:bar]).to be :foo
102
104
  end
105
+
103
106
  it 'creates accessor methods' do
104
107
  foo = TestObject.new
105
108
  expect(foo).to respond_to :foo
@@ -116,4 +119,27 @@ describe Cot::Frame do
116
119
  expect(foo.foo).to eq 'this is foo'
117
120
  end
118
121
  end
122
+
123
+ context 'errors' do
124
+ it 'has an errors property' do
125
+ expect(@foo).to respond_to :errors
126
+ expect(@foo.errors).to be_empty
127
+ end
128
+ end
129
+
130
+ context 'errors=' do
131
+ it 'sets errors' do
132
+ @foo.errors = { status: 200 }
133
+ expect(@foo.errors[:status]).to eq 200
134
+ end
135
+ end
136
+ context 'enum' do
137
+ it 'is not implemented' do
138
+ expect do
139
+ class TestObject < Cot::Frame
140
+ enum 'asdf'
141
+ end
142
+ end.to raise_exception StandardError
143
+ end
144
+ end
119
145
  end
data/spec/spec_helper.rb CHANGED
@@ -2,6 +2,9 @@ require 'simplecov'
2
2
 
3
3
  ENV['RAILS_ENV'] ||= 'test'
4
4
 
5
+ require 'simplecov'
6
+ SimpleCov.start
7
+
5
8
  require 'cot'
6
9
  require 'rspec'
7
10
  require 'rspec/its'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joseph Henrich
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-29 00:00:00.000000000 Z
11
+ date: 2014-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -127,9 +127,11 @@ files:
127
127
  - Rakefile
128
128
  - cot.gemspec
129
129
  - lib/cot.rb
130
+ - lib/cot/collection.rb
130
131
  - lib/cot/frame.rb
131
132
  - lib/cot/rspec/matchers.rb
132
133
  - lib/cot/version.rb
134
+ - spec/lib/cot/collection_spec.rb
133
135
  - spec/lib/cot/frame_spec.rb
134
136
  - spec/spec_helper.rb
135
137
  homepage: http://github.com/crimsonknave/cot
@@ -151,10 +153,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
153
  version: '0'
152
154
  requirements: []
153
155
  rubyforge_project:
154
- rubygems_version: 2.1.10
156
+ rubygems_version: 2.1.9
155
157
  signing_key:
156
158
  specification_version: 4
157
159
  summary: Simplifies creating models for rest based resources
158
160
  test_files:
161
+ - spec/lib/cot/collection_spec.rb
159
162
  - spec/lib/cot/frame_spec.rb
160
163
  - spec/spec_helper.rb