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.
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/Gemfile +3 -0
- data/Guardfile +5 -0
- data/LICENCE +7 -0
- data/README.md +19 -0
- data/api_remarks.txt +5 -0
- data/lib/pipe_line_dealer/client/connection.rb +71 -0
- data/lib/pipe_line_dealer/client.rb +27 -0
- data/lib/pipe_line_dealer/collection/concerns/create_and_update.rb +25 -0
- data/lib/pipe_line_dealer/collection/concerns/fetching.rb +64 -0
- data/lib/pipe_line_dealer/collection/concerns/results_fetcher.rb +64 -0
- data/lib/pipe_line_dealer/collection/concerns.rb +6 -0
- data/lib/pipe_line_dealer/collection.rb +24 -0
- data/lib/pipe_line_dealer/custom_field/collection.rb +18 -0
- data/lib/pipe_line_dealer/custom_fields.rb +59 -0
- data/lib/pipe_line_dealer/error/connection.rb +17 -0
- data/lib/pipe_line_dealer/error/invalid_attribute.rb +29 -0
- data/lib/pipe_line_dealer/error/no_such_custom_field.rb +12 -0
- data/lib/pipe_line_dealer/error.rb +9 -0
- data/lib/pipe_line_dealer/limits.rb +7 -0
- data/lib/pipe_line_dealer/model/base/concern/persistance.rb +69 -0
- data/lib/pipe_line_dealer/model/base.rb +133 -0
- data/lib/pipe_line_dealer/model/company/custom_field.rb +7 -0
- data/lib/pipe_line_dealer/model/company.rb +37 -0
- data/lib/pipe_line_dealer/model/custom_field.rb +73 -0
- data/lib/pipe_line_dealer/model/note.rb +32 -0
- data/lib/pipe_line_dealer/model/person/custom_field.rb +7 -0
- data/lib/pipe_line_dealer/model/person.rb +36 -0
- data/lib/pipe_line_dealer/version.rb +10 -0
- data/lib/pipe_line_dealer.rb +44 -0
- data/pipe_line_dealer.gemspec +45 -0
- data/spec/acceptance/companies/creation_spec.rb +31 -0
- data/spec/acceptance/companies/custom_fields_spec.rb +7 -0
- data/spec/acceptance/companies/updating_spec.rb +35 -0
- data/spec/acceptance/people/creation_spec.rb +19 -0
- data/spec/collection_spec.rb +166 -0
- data/spec/custom_fields_spec.rb +114 -0
- data/spec/helper.rb +32 -0
- data/spec/models/base/concern/persistance_spec.rb +55 -0
- data/spec/models/base_spec.rb +32 -0
- data/spec/models/custom_field_spec.rb +127 -0
- data/spec/smell_spec.rb +6 -0
- data/spec/support/acceptance_helper.rb +39 -0
- data/spec/support/collection_helper.rb +8 -0
- data/spec/support/connection_helper.rb +9 -0
- data/spec/support/pld_cleaner.rb +16 -0
- data/spec/support/test_model.rb +6 -0
- data/todo.txt +6 -0
- 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,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,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,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,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
|