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,114 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
describe PipeLineDealer::CustomFields do
|
4
|
+
before { pending "TODO" }
|
5
|
+
include ConnectionHelper
|
6
|
+
|
7
|
+
class ModelWithCustomFields < PLD::Model::Base
|
8
|
+
@collection_url = "models"
|
9
|
+
@model_attribute_name = "model"
|
10
|
+
@custom_field_client_method = :model_custom_fields
|
11
|
+
|
12
|
+
attrs :name
|
13
|
+
|
14
|
+
include PLD::CustomFields
|
15
|
+
end
|
16
|
+
|
17
|
+
class CustomModelField < PipeLineDealer::CustomField
|
18
|
+
@collection_url = "admin/model_custom_field_labels"
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:collection) { PLD::Collection.new(client, klass: ModelWithCustomFields) }
|
22
|
+
|
23
|
+
let(:custom_attributes) { {
|
24
|
+
"custom_label_90" => 42,
|
25
|
+
"custom_label_91" => "Yeah"
|
26
|
+
} }
|
27
|
+
|
28
|
+
let(:custom_field_labels) { {
|
29
|
+
"entries"=>[
|
30
|
+
{
|
31
|
+
"id"=>90,
|
32
|
+
"name"=>"TheAnswerForEverything",
|
33
|
+
"is_required"=>false,
|
34
|
+
"field_type"=>"numeric"
|
35
|
+
},
|
36
|
+
{
|
37
|
+
"id"=>91,
|
38
|
+
"name"=>"Really?",
|
39
|
+
"is_required"=>false,
|
40
|
+
"field_type"=>"text"
|
41
|
+
}
|
42
|
+
],
|
43
|
+
"pagination" => {"page" => 1, "pages" => 1, "per_page" => 2, "total" => 2}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
subject { ModelWithCustomFields.new(collection: collection, persisted: true, attributes: { "id" => 123, name: "Springest", custom_fields: custom_attributes} ) }
|
48
|
+
|
49
|
+
context "reading custom fields" do
|
50
|
+
before { client.stub(:model_custom_fields).and_return { PLD::CustomField::Collection.new(client, klass: CustomModelField, cache_key: :custom_field_cache_key) } }
|
51
|
+
|
52
|
+
let(:custom_field_models) do
|
53
|
+
custom_field_labels.collect { |label| CustomModelField.new(collection: model_custom_fields, persisted: true, attributes: label) }
|
54
|
+
end
|
55
|
+
|
56
|
+
it "fetches the translation map" do
|
57
|
+
pending
|
58
|
+
# connection.should_receive(:get).once.with("admin/model_custom_field_labels.json", anything()).and_return(custom_field_labels)
|
59
|
+
connection.should_receive(:cache).once.with(:custom_field_cache_key).and_return(custom_field_labels)
|
60
|
+
subject.custom_fields
|
61
|
+
end
|
62
|
+
|
63
|
+
it "translates the custom fields to recognizable labels" do
|
64
|
+
connection.should_receive(:get).once.with("admin/model_custom_field_labels.json", anything()).and_return(custom_field_labels)
|
65
|
+
|
66
|
+
subject.custom_fields.should == {
|
67
|
+
"TheAnswerForEverything" => 42,
|
68
|
+
"Really?" => "Yeah"
|
69
|
+
}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "storing" do
|
74
|
+
before { client.stub(:model_custom_fields).and_return { PLD::CustomField::Collection.new(client, klass: CustomModelField) } }
|
75
|
+
|
76
|
+
it "reposts the correct attributes" do
|
77
|
+
expected_attributes = {
|
78
|
+
"model" => {
|
79
|
+
"name" => "Springest",
|
80
|
+
"custom_fields" => custom_attributes
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
# TODO: should do this only once!
|
85
|
+
connection.should_receive(:get).exactly(4).times.with("admin/model_custom_field_labels.json", anything()).and_return(custom_field_labels)
|
86
|
+
connection.should_receive(:put).once.with("models/123.json", expected_attributes)
|
87
|
+
|
88
|
+
subject.save
|
89
|
+
end
|
90
|
+
|
91
|
+
let(:updated_custom_attributes) { {
|
92
|
+
"custom_label_90" => 43,
|
93
|
+
"custom_label_91" => "Whoo"
|
94
|
+
} }
|
95
|
+
|
96
|
+
it "posts the correct change" do
|
97
|
+
expected_attributes = {
|
98
|
+
"model" => {
|
99
|
+
"name" => "Springest",
|
100
|
+
"custom_fields" => updated_custom_attributes
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
# TODO: should do this only once!
|
105
|
+
connection.should_receive(:get).exactly(4).times.with("admin/model_custom_field_labels.json", anything()).and_return(custom_field_labels)
|
106
|
+
connection.should_receive(:put).once.with("models/123.json", expected_attributes)
|
107
|
+
|
108
|
+
|
109
|
+
subject.custom_fields["TheAnswerForEverything"] = 43
|
110
|
+
subject.custom_fields["Really?"] = "Whoo"
|
111
|
+
subject.save
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/spec/helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
Bundler.setup
|
2
|
+
|
3
|
+
unless ENV["NO_COVERAGE"]
|
4
|
+
require "simplecov"
|
5
|
+
SimpleCov.start do
|
6
|
+
add_filter "spec"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
require "pipe_line_dealer"
|
11
|
+
require "webmock/rspec"
|
12
|
+
require "reek/spec"
|
13
|
+
|
14
|
+
# Load support files
|
15
|
+
Dir[File.expand_path("../support/**/*.rb", __FILE__)].each { |f| require f }
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
config.filter_run focus: true
|
19
|
+
|
20
|
+
# Do not run the acceptance tests by default.
|
21
|
+
if ENV["ACCEPTANCE"] == "true"
|
22
|
+
puts "Running acceptance specs!"
|
23
|
+
AcceptanceHelper.check_api_key!
|
24
|
+
else
|
25
|
+
puts "Skipping acceptance specs"
|
26
|
+
config.filter_run_excluding acceptance: true
|
27
|
+
end
|
28
|
+
|
29
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
30
|
+
config.run_all_when_everything_filtered = true
|
31
|
+
config.include Reek::Spec
|
32
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
describe PipeLineDealer::Model::Base::Concern::Persistance do
|
4
|
+
include CollectionHelper
|
5
|
+
|
6
|
+
context "routing (url&method)" do
|
7
|
+
context "non persisted models" do
|
8
|
+
context "build by collection" do
|
9
|
+
subject { collection.new }
|
10
|
+
|
11
|
+
it "builds a non persisted model" do
|
12
|
+
subject.persisted?.should == false
|
13
|
+
end
|
14
|
+
|
15
|
+
it "builds a non persisted model" do
|
16
|
+
subject.persisted?.should == false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when saved" do
|
21
|
+
subject { collection.new(name: "Springest") }
|
22
|
+
after(:each) { subject.save }
|
23
|
+
|
24
|
+
it "uses the POST method" do
|
25
|
+
connection.should_receive(:post).and_return([200, {}])
|
26
|
+
end
|
27
|
+
|
28
|
+
it "posts to the correct address" do
|
29
|
+
connection.should_receive(:post).with("test_models.json", anything).and_return([200, {}])
|
30
|
+
end
|
31
|
+
|
32
|
+
it "posts the correct attributes" do
|
33
|
+
connection.should_receive(:post).with(anything, "moeha" => { "name" => "Springest" }).and_return([200, {}])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "persisted models" do
|
39
|
+
subject { TestModel.new(collection: collection, persisted: true, attributes: { "id" => 123, name: "Springest"} ) }
|
40
|
+
after(:each) { subject.save }
|
41
|
+
|
42
|
+
it "uses the PUT method" do
|
43
|
+
connection.should_receive(:put).and_return([200, {}])
|
44
|
+
end
|
45
|
+
|
46
|
+
it "posts to the correct address" do
|
47
|
+
connection.should_receive(:put).with("test_models/123.json", anything).and_return([200, {}])
|
48
|
+
end
|
49
|
+
|
50
|
+
it "posts the correct attributes" do
|
51
|
+
connection.should_receive(:put).with(anything, "moeha" => { "name" => "Springest" }).and_return([200, {}])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
describe PLD::Model::Base do
|
4
|
+
subject { TestModel }
|
5
|
+
|
6
|
+
context "initialization" do
|
7
|
+
let(:model) { subject.new(attributes: {name: "Springest"}) }
|
8
|
+
|
9
|
+
it "can access the name by the name method" do
|
10
|
+
model.name.should == "Springest"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "can access the name by via attributes['name']" do
|
14
|
+
model.attributes['name'].should == "Springest"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "can access the name by via attributes[:name]" do
|
18
|
+
model.attributes[:name].should == "Springest"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "setting attributes" do
|
23
|
+
let(:model) { subject.new() }
|
24
|
+
context "name is set using accessor" do
|
25
|
+
before { model.name = "Springest" }
|
26
|
+
|
27
|
+
it "is readable via the accessor" do
|
28
|
+
model.name.should == "Springest"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
module PipeLineDealer
|
4
|
+
describe CustomField do
|
5
|
+
let(:model) { nil }
|
6
|
+
|
7
|
+
describe "decode" do
|
8
|
+
context "numeric" do
|
9
|
+
before { subject.field_type = "numeric" }
|
10
|
+
|
11
|
+
it "decodes correctly" do
|
12
|
+
subject.decode(model, 123).should == 123
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "text" do
|
17
|
+
before { subject.field_type = "text" }
|
18
|
+
|
19
|
+
it "decodes correctly" do
|
20
|
+
subject.decode(model, "Moehaha").should == "Moehaha"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "currency" do
|
25
|
+
before { subject.field_type = "currency" }
|
26
|
+
|
27
|
+
it "decodes correctly" do
|
28
|
+
subject.decode(model, 42).should == 42
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "dropdown" do
|
33
|
+
subject do
|
34
|
+
CustomField.new(attributes: {
|
35
|
+
"field_type" => "dropdown",
|
36
|
+
"custom_field_label_dropdown_entries" => [{"id" => 123, "value" => "My Item"}]
|
37
|
+
})
|
38
|
+
end
|
39
|
+
|
40
|
+
it "decodes correctly" do
|
41
|
+
subject.decode(model, 123).should == "My Item"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "multi_select" do
|
46
|
+
subject do
|
47
|
+
CustomField.new(attributes: {
|
48
|
+
"field_type" => "multi_select",
|
49
|
+
"custom_field_label_dropdown_entries" => [{"id" => 123, "value" => "My Item"}]
|
50
|
+
})
|
51
|
+
end
|
52
|
+
|
53
|
+
it "decodes correctly" do
|
54
|
+
subject.decode(model, [123]).should == ["My Item"]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "Unkown type" do
|
59
|
+
before { subject.field_type = "not-known" }
|
60
|
+
|
61
|
+
it "throws an exception" do
|
62
|
+
expect { subject.decode(model, 42) }.to raise_error
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "encode" do
|
68
|
+
context "numeric" do
|
69
|
+
before { subject.field_type = "numeric" }
|
70
|
+
|
71
|
+
it "encodes correctly" do
|
72
|
+
subject.encode(model, 123).should == 123
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "text" do
|
77
|
+
before { subject.field_type = "text" }
|
78
|
+
|
79
|
+
it "encodes correctly" do
|
80
|
+
subject.encode(model, "Moehaha").should == "Moehaha"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "currency" do
|
85
|
+
before { subject.field_type = "currency" }
|
86
|
+
|
87
|
+
it "encodes correctly" do
|
88
|
+
subject.encode(model, 42).should == 42
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "dropdown" do
|
93
|
+
subject do
|
94
|
+
CustomField.new(attributes: {
|
95
|
+
"field_type" => "dropdown",
|
96
|
+
"custom_field_label_dropdown_entries" => [{"id" => 123, "value" => "My Item"}]
|
97
|
+
})
|
98
|
+
end
|
99
|
+
|
100
|
+
it "encodes correctly" do
|
101
|
+
subject.encode(model, "My Item").should == 123
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "multi_select" do
|
106
|
+
subject do
|
107
|
+
CustomField.new(attributes: {
|
108
|
+
"field_type" => "multi_select",
|
109
|
+
"custom_field_label_dropdown_entries" => [{"id" => 123, "value" => "My Item"}]
|
110
|
+
})
|
111
|
+
end
|
112
|
+
|
113
|
+
it "encodes correctly" do
|
114
|
+
subject.encode(model, ["My Item"]).should == [123]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context "Unkown type" do
|
119
|
+
before { subject.field_type = "not-known" }
|
120
|
+
|
121
|
+
it "throws an exception" do
|
122
|
+
expect { subject.encode(model, 42) }.to raise_error
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
data/spec/smell_spec.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module AcceptanceHelper extend ActiveSupport::Concern
|
2
|
+
|
3
|
+
class << self
|
4
|
+
KEY_FILE = File.expand_path("../../api.key", __FILE__)
|
5
|
+
|
6
|
+
def check_api_key!
|
7
|
+
if not find_api_key
|
8
|
+
puts
|
9
|
+
$stderr.puts "No API key found to run the acceptance tests!"
|
10
|
+
puts "To specify a API key, either:"
|
11
|
+
puts " 1) use the API_KEY environmental variable!"
|
12
|
+
puts " 2) create a 'spec/api.key' file which contains the API key."
|
13
|
+
puts
|
14
|
+
exit(1)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def find_api_key
|
19
|
+
ENV["API_KEY"] || File.exists?(KEY_FILE) && File.read(KEY_FILE).chomp.strip
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
included do
|
24
|
+
let(:api_key) { AcceptanceHelper.find_api_key }
|
25
|
+
let(:client) { PLD::Client.new(AcceptanceHelper.find_api_key) }
|
26
|
+
|
27
|
+
around do |example|
|
28
|
+
if example.metadata.has_key? :acceptance
|
29
|
+
WebMock.allow_net_connect!
|
30
|
+
|
31
|
+
PLDCleaner.clean!(client)
|
32
|
+
end
|
33
|
+
|
34
|
+
example.run
|
35
|
+
|
36
|
+
WebMock.disable_net_connect! if example.metadata.has_key? :acceptance
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module PLDCleaner
|
2
|
+
extend self
|
3
|
+
|
4
|
+
COLLECTION_NAMES = [:companies, :people]
|
5
|
+
|
6
|
+
def clean!(client)
|
7
|
+
COLLECTION_NAMES.each do |collection_name|
|
8
|
+
collection = client.send(collection_name)
|
9
|
+
|
10
|
+
collection.each do |model|
|
11
|
+
#CRITICAL
|
12
|
+
model.destroy || raise("Could not remove #{model.inspect}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|