pipe_line_dealer 0.1.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.
Files changed (51) hide show
  1. data/.gitignore +3 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +3 -0
  5. data/Guardfile +5 -0
  6. data/LICENCE +7 -0
  7. data/README.md +19 -0
  8. data/api_remarks.txt +5 -0
  9. data/lib/pipe_line_dealer/client/connection.rb +71 -0
  10. data/lib/pipe_line_dealer/client.rb +27 -0
  11. data/lib/pipe_line_dealer/collection/concerns/create_and_update.rb +25 -0
  12. data/lib/pipe_line_dealer/collection/concerns/fetching.rb +64 -0
  13. data/lib/pipe_line_dealer/collection/concerns/results_fetcher.rb +64 -0
  14. data/lib/pipe_line_dealer/collection/concerns.rb +6 -0
  15. data/lib/pipe_line_dealer/collection.rb +24 -0
  16. data/lib/pipe_line_dealer/custom_field/collection.rb +18 -0
  17. data/lib/pipe_line_dealer/custom_fields.rb +59 -0
  18. data/lib/pipe_line_dealer/error/connection.rb +17 -0
  19. data/lib/pipe_line_dealer/error/invalid_attribute.rb +29 -0
  20. data/lib/pipe_line_dealer/error/no_such_custom_field.rb +12 -0
  21. data/lib/pipe_line_dealer/error.rb +9 -0
  22. data/lib/pipe_line_dealer/limits.rb +7 -0
  23. data/lib/pipe_line_dealer/model/base/concern/persistance.rb +69 -0
  24. data/lib/pipe_line_dealer/model/base.rb +133 -0
  25. data/lib/pipe_line_dealer/model/company/custom_field.rb +7 -0
  26. data/lib/pipe_line_dealer/model/company.rb +37 -0
  27. data/lib/pipe_line_dealer/model/custom_field.rb +73 -0
  28. data/lib/pipe_line_dealer/model/note.rb +32 -0
  29. data/lib/pipe_line_dealer/model/person/custom_field.rb +7 -0
  30. data/lib/pipe_line_dealer/model/person.rb +36 -0
  31. data/lib/pipe_line_dealer/version.rb +10 -0
  32. data/lib/pipe_line_dealer.rb +44 -0
  33. data/pipe_line_dealer.gemspec +45 -0
  34. data/spec/acceptance/companies/creation_spec.rb +31 -0
  35. data/spec/acceptance/companies/custom_fields_spec.rb +7 -0
  36. data/spec/acceptance/companies/updating_spec.rb +35 -0
  37. data/spec/acceptance/people/creation_spec.rb +19 -0
  38. data/spec/collection_spec.rb +166 -0
  39. data/spec/custom_fields_spec.rb +114 -0
  40. data/spec/helper.rb +32 -0
  41. data/spec/models/base/concern/persistance_spec.rb +55 -0
  42. data/spec/models/base_spec.rb +32 -0
  43. data/spec/models/custom_field_spec.rb +127 -0
  44. data/spec/smell_spec.rb +6 -0
  45. data/spec/support/acceptance_helper.rb +39 -0
  46. data/spec/support/collection_helper.rb +8 -0
  47. data/spec/support/connection_helper.rb +9 -0
  48. data/spec/support/pld_cleaner.rb +16 -0
  49. data/spec/support/test_model.rb +6 -0
  50. data/todo.txt +6 -0
  51. metadata +320 -0
@@ -0,0 +1,133 @@
1
+ require "json"
2
+ require "active_support/hash_with_indifferent_access"
3
+
4
+ module PipeLineDealer
5
+ module Model
6
+ class Base
7
+ include Concern::Persistance
8
+ attr_reader :attributes
9
+ attr_reader :id
10
+
11
+ def initialize options = {}
12
+ @options = options
13
+ @persisted = !!@options[:persisted]
14
+ @collection = @options[:collection]
15
+
16
+ import_attributes! @options[:attributes]
17
+ end
18
+
19
+ # TODO : remove check of methode bestaat
20
+ def attributes_for_saving(attributes)
21
+ attributes
22
+ end
23
+
24
+
25
+ def ==(other)
26
+ if other.kind_of?(self.class)
27
+ other.attributes == self.attributes
28
+ else
29
+ super(other)
30
+ end
31
+ end
32
+
33
+ def to_json
34
+ JSON.dump(@attributes)
35
+ end
36
+
37
+ def self.attrs *attrs
38
+ if attrs.last.kind_of?(Hash)
39
+ options = attrs.pop
40
+ else
41
+ options = {}
42
+ end
43
+
44
+ attrs.each do |attr|
45
+ pld_attr attr, options
46
+ end
47
+ end
48
+
49
+ def self.inherited(subklass)
50
+ @attributes ||= {}
51
+
52
+ # Copy all attributes to the children.
53
+ @attributes.each do |attr, options|
54
+ subklass.pld_attr attr, options
55
+ end
56
+ end
57
+
58
+ def self.pld_attr attr, options = {}
59
+ @attributes ||= {}
60
+ @attributes[attr] = options
61
+
62
+ # Getter
63
+ define_method attr do
64
+ @attributes[attr.to_s]
65
+ end
66
+
67
+ # Setter
68
+ define_method "#{attr}=".to_sym do |value|
69
+ @attributes[attr.to_s] = value
70
+ end
71
+ end
72
+
73
+ def to_s
74
+ "<PipeLineDealer::Model:#{__id__} klass=#{self.class.name} id=#{@id} attributes=#{@attributes.inspect}>"
75
+ end
76
+
77
+ protected
78
+
79
+ def import_attributes! attributes
80
+ @attributes = stringify_keys(attributes || {})
81
+ @id = @attributes.delete(:id)
82
+
83
+ # Give subclasses the opportunity to hook in here.
84
+ process_attributes if respond_to?(:process_attributes)
85
+
86
+ check_for_non_existent_attributes!
87
+ end
88
+
89
+ def model_attribute_name
90
+ self.class.instance_variable_get(:@model_attribute_name) || raise("#{self.class.inspect}::@model_attribute_name is missing!")
91
+ end
92
+
93
+ # Recursively converts a hash structure with symbol keys to a hash
94
+ # with indifferent keys
95
+ def stringify_keys original
96
+ result = HashWithIndifferentAccess.new
97
+
98
+ original.each do |key, value|
99
+ result[key] = stringify_value(value)
100
+ end
101
+
102
+ result
103
+ end
104
+
105
+ def stringify_value value
106
+ case value
107
+ when String, Fixnum, NilClass, FalseClass, TrueClass
108
+ return value
109
+ when Hash, HashWithIndifferentAccess
110
+ return stringify_keys(value)
111
+ when Array
112
+ return value.collect { |item| stringify_value(item) }
113
+ else
114
+ raise "Unkown type: #{value.class}"
115
+ end
116
+ end
117
+
118
+ def valid_attribute_names
119
+ self.class.instance_variable_get(:@attributes).keys || []
120
+ end
121
+
122
+ def check_for_non_existent_attributes!
123
+ attribute_keys = @attributes.keys.collect(&:to_sym)
124
+
125
+ invalid_attributes = attribute_keys - valid_attribute_names
126
+
127
+ if invalid_attributes.any?
128
+ raise Error::InvalidAttributeName.new(self.class, invalid_attributes.first)
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,7 @@
1
+ module PipeLineDealer
2
+ class Company
3
+ class CustomField < PipeLineDealer::CustomField
4
+ @collection_url = "admin/company_custom_field_labels"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,37 @@
1
+ module PipeLineDealer
2
+ class Company < Model::Base
3
+ @collection_url = "companies"
4
+ @model_attribute_name = "company"
5
+ @custom_field_client_method = :custom_company_fields
6
+
7
+ include CustomFields
8
+
9
+ attrs :address_1, :address_2, :city, :country,
10
+ :name, :description,
11
+ :image_thumb_url,
12
+ :import_id,
13
+ :email, :fax, :phone1, :phone1_desc, :phone2, :phone2_desc, :phone3, :phone3_desc, :phone4, :phone4_desc, :postal_code, :state, :web,
14
+ :total_pipeline, :won_deals_total,
15
+ :created_at, :updated_at
16
+
17
+
18
+ def attributes_for_saving_with_company attributes
19
+ attributes = attributes_for_saving_without_company(attributes)
20
+
21
+ attributes.delete(:total_pipeline)
22
+ attributes.delete(:won_deals)
23
+ attributes.delete(:won_deals_total)
24
+ attributes.delete(:image_thumb_url) if attributes[:image_thumb_url] == "/images/thumb/missing_company.png"
25
+
26
+ attributes
27
+ end
28
+
29
+ alias_method_chain :attributes_for_saving, :company
30
+
31
+ def notes
32
+ Collection.new(@collection.client, klass: Note, cached: false).\
33
+ where(query: { company_id: self.id }).\
34
+ on_new_defaults(company_id: self.id)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,73 @@
1
+ module PipeLineDealer
2
+ class CustomField < Model::Base
3
+ attrs :name, :is_required, :field_type
4
+ attr_reader :dropdown_entries
5
+
6
+ def process_attributes
7
+ @dropdown_entries = @attributes.delete(:custom_field_label_dropdown_entries)
8
+ end
9
+
10
+ def decode(model, value)
11
+ case field_type
12
+ when "numeric" then return value
13
+ when "text" then return value
14
+ when "currency" then return value
15
+ when "dropdown" then return decode_dropdown(model, value)
16
+ when "multi_select" then return decode_multi_select(model, value)
17
+ when "multi_association" then return decode_multi_association(model, value)
18
+ else; raise "Unkown PLD field type! #{field_type.inspect}"
19
+ end
20
+ end
21
+
22
+ def encode(model, value)
23
+ case field_type
24
+ when "numeric" then return value
25
+ when "text" then return value
26
+ when "currency" then return value
27
+ when "dropdown" then return encode_dropdown(model, value)
28
+ when "multi_select" then return encode_multi_select(model, value)
29
+ when "multi_association" then return encode_multi_association(model, value)
30
+ else; raise "Unkown PLD field type! #{field_type.inspect}"
31
+ end
32
+ end
33
+
34
+ protected
35
+
36
+ def decode_dropdown(model, id)
37
+ @dropdown_entries.each do |entry|
38
+ return entry["value"] if entry["id"] == id
39
+ end
40
+
41
+ raise Error::InvalidAttributeValue.new(model, name, id)
42
+ end
43
+
44
+ def encode_dropdown(model, value)
45
+ @dropdown_entries.each do |entry|
46
+ return entry["id"] if entry["value"] == value
47
+ end
48
+
49
+ raise Error::InvalidAttributeValue.new(model, name, value)
50
+ end
51
+
52
+ def decode_multi_select(model, ids)
53
+ ids.collect do |id|
54
+ decode_dropdown(model, id)
55
+ end
56
+ end
57
+
58
+ def encode_multi_select(model, values)
59
+ values.collect do |value|
60
+ encode_dropdown(model, value)
61
+ end
62
+ end
63
+
64
+ #TODO: Not implemented yet.
65
+ def decode_multi_association(model, value)
66
+ value
67
+ end
68
+
69
+ def encode_multi_association(model, value)
70
+ value
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,32 @@
1
+ module PipeLineDealer
2
+ class Note < Model::Base
3
+ @collection_url = "notes"
4
+ @model_attribute_name = "note"
5
+
6
+ # include CustomFields
7
+
8
+ @custom_field_client_method = :custom_person_fields
9
+ attrs :deal, :deal_id, :person_id, :company_id, :title, :created_by_user_id, :note_category_id, :created_at, :updated_at, :company, :person, :created_by_user, :note_category, :content
10
+
11
+ def process_attributes
12
+ # TODO: Remove these convenience objects for now
13
+ end
14
+
15
+ def attributes_for_saving_with_note attributes
16
+ attributes = attributes_for_saving_without_note(attributes)
17
+
18
+ attributes.delete(:deal)
19
+ attributes.delete(:created_by_user)
20
+ attributes.delete(:note_category)
21
+
22
+ attributes.delete(:created_at)
23
+ attributes.delete(:updated_at)
24
+ attributes.delete(:company)
25
+ attributes.delete(:person)
26
+
27
+ attributes
28
+ end
29
+
30
+ alias_method_chain :attributes_for_saving, :note
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ module PipeLineDealer
2
+ class Person
3
+ class CustomField < PipeLineDealer::CustomField
4
+ @collection_url = "admin/person_custom_field_labels"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,36 @@
1
+ module PipeLineDealer
2
+ class Person < Model::Base
3
+ @collection_url = "people"
4
+ @model_attribute_name = "person"
5
+ @custom_field_client_method = :custom_person_fields
6
+
7
+ # include CustomFields
8
+
9
+ attrs :company, :company_id, :company_name, :created_at, :deal_ids, :deals, :email, :email2, :facebook_url, :fax, :first_name, :full_name, :home_address_1, :home_address_2, :home_city, :home_country, :home_email, :home_phone, :home_postal_code, :home_state, :image_thumb_url, :instant_message, :last_name, :lead_source, :lead_status, :linked_in_url, :mobile, :phone, :position, :predefined_contacts_tag_ids, :predefined_contacts_tags, :total_pipeline, :twitter, :type, :updated_at, :user, :user_id, :viewed_at, :website, :won_deals_total, :work_address_1, :work_address_2, :work_city, :work_country, :work_postal_code, :work_state
10
+
11
+ def process_attributes
12
+ @attributes.delete(:custom_fields)
13
+ end
14
+
15
+ #TODO: make sure that removeing one of these causes problems.
16
+ def attributes_for_saving_with_person attributes
17
+ attributes = attributes_for_saving_without_person(attributes)
18
+
19
+ attributes.delete(:company)
20
+ attributes.delete(:deals)
21
+ attributes.delete(:won_deals_total)
22
+ attributes.delete(:lead_status)
23
+ attributes.delete(:viewed_at)
24
+ attributes.delete(:deal_ids)
25
+ attributes.delete(:predefined_contacts_tag_ids)
26
+ attributes.delete(:user_id)
27
+ attributes.delete(:user)
28
+
29
+ attributes.delete(:image_thumb_url) if attributes[:image_thumb_url] == "/images/thumb/missing.png"
30
+
31
+ attributes
32
+ end
33
+
34
+ alias_method_chain :attributes_for_saving, :person
35
+ end
36
+ end
@@ -0,0 +1,10 @@
1
+ module PipeLineDealer
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ PATCH = 0
6
+ BETA = nil
7
+ end
8
+
9
+ VERSION = [Version::MAJOR, Version::MINOR, Version::PATCH, Version::BETA].reject(&:nil?).collect(&:to_s).join(".")
10
+ end
@@ -0,0 +1,44 @@
1
+ require "active_support/concern"
2
+ require "faraday"
3
+ require "multi_json"
4
+
5
+ module PipeLineDealer
6
+ %W{
7
+ limits
8
+ version
9
+
10
+ error
11
+ error/no_such_custom_field
12
+ error/invalid_attribute
13
+ error/connection
14
+
15
+ collection/concerns
16
+ collection/concerns/fetching
17
+ collection/concerns/results_fetcher
18
+ collection/concerns/create_and_update
19
+ collection
20
+
21
+ model/base/concern/persistance
22
+ model/base
23
+ model/custom_field
24
+
25
+ custom_fields
26
+ custom_field/collection
27
+
28
+ model/company
29
+ model/company/custom_field
30
+
31
+ model/person
32
+ model/person/custom_field
33
+
34
+ model/note
35
+
36
+ client/connection
37
+ client
38
+ }.each { |file| require(File.join("pipe_line_dealer", file))}
39
+ end
40
+
41
+ # Shortcut :)
42
+ if not defined?(PLD)
43
+ PLD = PipeLineDealer
44
+ end
@@ -0,0 +1,45 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "pipe_line_dealer/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "pipe_line_dealer"
7
+ s.version = PipeLineDealer::VERSION
8
+ s.authors = ["Maarten Hoogendoorn"]
9
+ s.email = ["maarten@springest.com"]
10
+ s.homepage = "http://github.com/moretea/pipe_line_dealer"
11
+ s.summary = "A Ruby library that implements the PipelineDeals.com API."
12
+ s.description = s.summary
13
+
14
+ s.required_ruby_version = ">=1.9.2"
15
+
16
+ # Dependencies
17
+ s.add_dependency "faraday", "~> 0.8.0"
18
+ s.add_dependency "faraday_middleware", "~> 0.9.0"
19
+ s.add_dependency "multi_json", "~> 1.3.6"
20
+ s.add_dependency "activesupport", ">= 3.2.0"
21
+
22
+ s.add_development_dependency "debugger"
23
+ s.add_development_dependency "rspec"
24
+ s.add_development_dependency "rake"
25
+ s.add_development_dependency "webmock"
26
+ s.add_development_dependency "simplecov"
27
+ s.add_development_dependency "guard-rspec"
28
+ s.add_development_dependency "rb-inotify"
29
+ s.add_development_dependency "fuubar"
30
+ s.add_development_dependency "reek"
31
+
32
+ # Make development a charm
33
+ if RUBY_PLATFORM.include?("darwin")
34
+ s.add_development_dependency "growl", "~> 1.0.3"
35
+ s.add_development_dependency "rb-fsevent"
36
+ elsif RUBY_PLATFORM.include?("linux")
37
+ s.add_development_dependency "rb-inotify"
38
+ end
39
+
40
+ # Files
41
+ s.files = `git ls-files`.split("\n")
42
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
43
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
44
+ s.require_paths = ["lib"]
45
+ end
@@ -0,0 +1,31 @@
1
+ require "helper"
2
+
3
+ describe "Company", :acceptance do
4
+ describe "creation" do
5
+ include AcceptanceHelper
6
+
7
+ context "using client.companies.new" do
8
+ let(:company) { client.companies.new(name: "Meh") }
9
+
10
+ context "with a valid model" do
11
+ before { company.name = "Meh" }
12
+
13
+ context "when saved" do
14
+ it "returns a model" do
15
+ company.save.should be_kind_of PLD::Model::Base
16
+ end
17
+ end
18
+ end
19
+
20
+ context "with an invalid model" do
21
+ before { company.name = nil }
22
+
23
+ context "when saved" do
24
+ it "raises an error" do
25
+ expect { company.save}.to raise_error PipeLineDealer::Error::Connection::Unprocessable
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,7 @@
1
+ require "helper"
2
+
3
+ describe "Company", :acceptance do
4
+ describe "custom fields" do
5
+ pending "Can't test this (yet), since it's not accessible via the API."
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ require "helper"
2
+
3
+ describe "Company", :acceptance do
4
+ describe "updating" do
5
+ include AcceptanceHelper
6
+ let(:company) { client.companies.create(name: "Old") }
7
+
8
+ context "using client.companies.new" do
9
+ context "with a valid model" do
10
+ before { company.name = "new" }
11
+
12
+ context "when saved" do
13
+ it "returns a model" do
14
+ company.save.should be_kind_of PLD::Model::Base
15
+ end
16
+
17
+ it "has the new name" do
18
+ company.save
19
+ client.companies.find(company.id).name.should == "new"
20
+ end
21
+ end
22
+ end
23
+
24
+ context "with an invalid model" do
25
+ before { company.name = nil }
26
+
27
+ context "when saved" do
28
+ it "raises an error" do
29
+ expect { company.save }.to raise_error PipeLineDealer::Error::Connection::Unprocessable
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ require "helper"
2
+
3
+ describe "Person", :acceptance do
4
+ describe "creation" do
5
+ include AcceptanceHelper
6
+
7
+ context "using client.people.new" do
8
+ let(:person) { client.people.new(first_name: "Maarten", last_name: "Hoogendoorn") }
9
+
10
+ before { person.first_name = "MoreTea" }
11
+
12
+ context "when saved" do
13
+ it "returns a model" do
14
+ person.save.should be_kind_of PLD::Model::Base
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,166 @@
1
+ require "helper"
2
+
3
+ describe PLD::Collection do
4
+ include ConnectionHelper
5
+
6
+ subject { PLD::Collection.new(client, klass: TestModel) }
7
+
8
+ context "transparant pagination" do
9
+ let(:expected_params_a) { ["test_models.json", { page: 1, per_page: 200 } ] }
10
+ let(:expected_params_b) { ["test_models.json", { page: 2, per_page: 200 } ] }
11
+
12
+ let(:response_a) do
13
+ [
14
+ 200, # Status code
15
+ { # 'JSON' body
16
+ "pagination" => {
17
+ "page" => 1,
18
+ "pages" => 2,
19
+ "per_page" => 1,
20
+ "total" => 2,
21
+ "url" => '/resource',
22
+ },
23
+ "entries" => [model_a.attributes]
24
+ }
25
+ ]
26
+ end
27
+
28
+ let(:response_b) do
29
+ [
30
+ 200, # Status code
31
+ { # 'JSON' body
32
+ "pagination" => {
33
+ "page" => 2,
34
+ "pages" => 2,
35
+ "per_page" => 1,
36
+ "total" => 2,
37
+ "url" => '/resource',
38
+ },
39
+ "entries" => [model_b.attributes]
40
+ }
41
+ ]
42
+ end
43
+
44
+ let(:model_a) { TestModel.new(collection: subject, attributes: { name: "Maarten" }) }
45
+ let(:model_b) { TestModel.new(collection: subject, attributes: { name: "Hoogendoorn" }) }
46
+
47
+ it "fetches the correct models" do
48
+ connection.should_receive(:get).ordered.once.with(*expected_params_a).and_return(response_a)
49
+ connection.should_receive(:get).ordered.once.with(*expected_params_b).and_return(response_b)
50
+
51
+ subject.all.to_a.should =~ [model_a, model_b]
52
+ end
53
+
54
+ it "returns records that are not new" do
55
+ connection.should_receive(:get).ordered.once.with(*expected_params_a).and_return(response_a)
56
+ connection.should_receive(:get).ordered.once.with(*expected_params_b).and_return(response_b)
57
+
58
+ a, b = subject.all.to_a
59
+
60
+ a.new_record?.should == false
61
+ b.new_record?.should == false
62
+ end
63
+ end
64
+
65
+ context "limit" do
66
+ let(:expected_params) { ["test_models.json", { page:1, per_page: 1} ] }
67
+
68
+ let(:response) do
69
+ [
70
+ 200, # Status code
71
+ { # 'JSON' body
72
+ "pagination" => {
73
+ "page" => 1,
74
+ "pages" => 2,
75
+ "per_page" => 1,
76
+ "total" => 2,
77
+ "url" => '/resource',
78
+ },
79
+ "entries" => [model_a.attributes]
80
+ }
81
+ ]
82
+ end
83
+
84
+ let(:model_a) { TestModel.new(collection: subject, attributes: { name: "Maarten"}) }
85
+
86
+ it "fetches only the resouces before the limit" do
87
+ connection.should_receive(:get).once.with(*expected_params).and_return(response)
88
+ subject.first.should == model_a
89
+ end
90
+ end
91
+
92
+ describe "cacheing" do
93
+ let(:response) do
94
+ [
95
+ 200, # Status code
96
+ {
97
+ "pagination" => {
98
+ "page" => 1,
99
+ "pages" => 1,
100
+ "per_page" => 1,
101
+ "total" => 1,
102
+ "url" => '/resource',
103
+ },
104
+ "entries" => [{}]
105
+ }
106
+ ]
107
+ end
108
+
109
+ before do
110
+ connection.stub(:get).and_return(response)
111
+ end
112
+
113
+ context "not cached" do
114
+ subject { PLD::Collection.new(client, klass: TestModel, cached: false) }
115
+
116
+ it "doesn't try to cache the result" do
117
+ connection.should_not_receive(:cache)
118
+ subject.all.to_a
119
+ end
120
+ end
121
+
122
+ context "cached" do
123
+ subject { PLD::Collection.new(client, klass: TestModel, cached: true) }
124
+
125
+ it "caches the request" do
126
+ connection.should_receive(:cache)
127
+ subject.all
128
+ end
129
+ end
130
+ end
131
+
132
+ context "building new objects" do
133
+ let(:new_object) { subject.new }
134
+
135
+ it "builds a model" do
136
+ new_object.should be_kind_of TestModel
137
+ end
138
+
139
+ context "initialize these objects" do
140
+ include CollectionHelper
141
+ subject { collection }
142
+
143
+ context "valid attributes" do
144
+ it "sets the valid attributes" do
145
+ model = collection.new(name: "Springest")
146
+ model.name.should == "Springest"
147
+ end
148
+ end
149
+
150
+ context "invalid attributes" do
151
+ context "invalid name" do
152
+ it "raises an exception" do
153
+ expect { collection.new(no_such_name: "Springest") }.to raise_error(PLD::Error::InvalidAttributeName)
154
+ end
155
+ end
156
+
157
+ context "invalid value" do
158
+ it "raises an exception" do
159
+ pending "TODO"
160
+ expect { collection.new(name: "Springest") }.to raise_error(PLD::Error::InvalidAttributeValue)
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end