printfection 1.0.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.
@@ -0,0 +1,59 @@
1
+ module Printfection
2
+ class Relation
3
+ include Enumerable
4
+ extend Forwardable
5
+ def_delegators :@children, :each, :first, :last, :size, :count, :length
6
+
7
+ attr_reader :parent, :children, :klass, :path, :keys, :actions
8
+
9
+ def initialize(options={})
10
+ options = {
11
+ parent: nil,
12
+ children: [],
13
+ klass: Hashie::Mash,
14
+ path: "",
15
+ keys: {},
16
+ actions: []
17
+ }.merge(options)
18
+
19
+ @parent = options.fetch(:parent)
20
+ @children = options.fetch(:children)
21
+ @klass = options.fetch(:klass)
22
+ @path = options.fetch(:path)
23
+ @keys = options.fetch(:keys)
24
+ @actions = options.fetch(:actions)
25
+
26
+ actions.each do |mod|
27
+ self.extend(mod)
28
+ end
29
+
30
+ children.each do |child|
31
+ apply_relation(child)
32
+ end
33
+ end
34
+
35
+ def uri
36
+ Util.join_uri(parent.uri, path)
37
+ end
38
+
39
+ def new(*args)
40
+ child = klass.new(*args)
41
+ apply_relation(child)
42
+ return child
43
+ end
44
+
45
+ private
46
+
47
+ def apply_relation(child)
48
+ keys.each do |primary, foreign|
49
+ child[foreign] = parent[primary]
50
+ end
51
+
52
+ if child.respond_to? :relation=
53
+ child.relation = self
54
+ end
55
+ end
56
+
57
+ end
58
+ end
59
+
@@ -0,0 +1,31 @@
1
+ module Printfection
2
+ class Resource < Hashie::Trash
3
+ include Hashie::Extensions::IndifferentAccess
4
+ include Hashie::Extensions::Coercion
5
+
6
+ property :object
7
+
8
+ attr_accessor :relation
9
+
10
+ def initialize(*args)
11
+ super
12
+ @_old = self.dup
13
+ end
14
+
15
+ def uri
16
+ base = self.relation.nil? ? self.class.uri : self.relation.uri
17
+ Util.join_uri(base, self.id)
18
+ end
19
+
20
+ def changes
21
+ keys.inject({}) do |diff, key|
22
+ unless self[key] == @_old[key]
23
+ diff[key] = self[key]
24
+ end
25
+ diff
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+
@@ -0,0 +1,11 @@
1
+ module Printfection
2
+ class Size < Resource
3
+ property :id, transform_with: Transforms::Integer
4
+ property :name
5
+ property :short_name
6
+
7
+ property :stock
8
+ coerce_key :stock, Hashie::Mash
9
+ end
10
+ end
11
+
@@ -0,0 +1,8 @@
1
+ module Printfection
2
+ module Transforms
3
+ Integer = lambda { |v| v.to_i }
4
+ Float = lambda { |v| v.to_f }
5
+ Date = lambda { |v| v.nil? ? nil : DateTime.parse(v) }
6
+ end
7
+ end
8
+
@@ -0,0 +1,8 @@
1
+ module Printfection
2
+ module Util
3
+ def self.join_uri(*args)
4
+ Array(args).join("/").gsub(/\/{2,}/, "/").chomp("/")
5
+ end
6
+ end
7
+ end
8
+
@@ -0,0 +1,4 @@
1
+ module Printfection
2
+ VERSION = "1.0.0"
3
+ end
4
+
@@ -0,0 +1,27 @@
1
+ require "json"
2
+ require "hashie"
3
+ require "restclient"
4
+ require "forwardable"
5
+
6
+ require "printfection/version"
7
+ require "printfection/util"
8
+ require "printfection/error"
9
+ require "printfection/api"
10
+ require "printfection/transforms"
11
+ require "printfection/relation"
12
+ require "printfection/resource"
13
+ require "printfection/actions"
14
+ require "printfection/address"
15
+ require "printfection/product"
16
+ require "printfection/size"
17
+ require "printfection/asset"
18
+ require "printfection/campaign"
19
+ require "printfection/item"
20
+ require "printfection/line_item"
21
+ require "printfection/manifest"
22
+ require "printfection/order"
23
+
24
+ module Printfection
25
+ extend API
26
+ end
27
+
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'printfection/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "printfection"
8
+ spec.version = Printfection::VERSION
9
+ spec.authors = ["Casey O'Hara"]
10
+ spec.email = ["casey.ohara@printfection.com"]
11
+ spec.summary = "Implementation of the Printfection API for Ruby"
12
+ spec.description = ""
13
+ spec.homepage = "https://github.com/printfection/printfection-ruby"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "hashie", "~> 3.3.1"
22
+ spec.add_dependency "rest-client", "~> 1.7.2"
23
+
24
+ spec.add_development_dependency "bundler", ">= 1.6.8"
25
+ spec.add_development_dependency "rake", "10.3.2"
26
+ spec.add_development_dependency "rspec", "3.1.0"
27
+ spec.add_development_dependency "codeclimate-test-reporter"
28
+ end
29
+
@@ -0,0 +1,83 @@
1
+ require 'printfection'
2
+
3
+ module Printfection
4
+ class Widget < Resource
5
+ extend Actions::Retrieve
6
+ extend Actions::List
7
+ extend Actions::Create
8
+ include Actions::Update
9
+ include Actions::Delete
10
+
11
+ property :id
12
+ property :size
13
+ property :quantity
14
+
15
+ def self.uri
16
+ "/widgets"
17
+ end
18
+ end
19
+
20
+ describe Actions::Retrieve, ".retrieve" do
21
+ it "returns an instance of the resource for the given id" do
22
+ json_data = double
23
+ widget = double
24
+
25
+ expect(Printfection).to receive(:get).with("/widgets/123").and_return(json_data)
26
+ expect(Widget).to receive(:new).with(json_data).and_return(widget)
27
+ expect(Widget.retrieve(123)).to eql widget
28
+ end
29
+ end
30
+
31
+ describe Actions::List, ".all" do
32
+ it "returns an array of instances of the resource" do
33
+ json_data1, json_data2 = double, double
34
+ widget1, widget2 = double, double
35
+
36
+ expect(Printfection).to receive(:get).
37
+ with("/widgets", {offset: 10, limit: 5}).
38
+ and_return([json_data1, json_data2])
39
+ expect(Widget).to receive(:new).with(json_data1).and_return(widget1)
40
+ expect(Widget).to receive(:new).with(json_data2).and_return(widget2)
41
+
42
+ expect(Widget.all(offset: 10, limit: 5)).to eql [widget1, widget2]
43
+ end
44
+ end
45
+
46
+ describe Actions::Create, ".create" do
47
+ it "creates, saves, and returns a new resource with the response data" do
48
+ params = double
49
+ json_data = double
50
+ new_widget = double
51
+
52
+ expect(Printfection).to receive(:post).
53
+ with("/widgets", params).
54
+ and_return(json_data)
55
+
56
+ expect(Widget).to receive(:new).
57
+ with(json_data).
58
+ and_return(new_widget)
59
+
60
+ widget = Widget.create(params)
61
+ expect(widget).to eql new_widget
62
+ end
63
+ end
64
+
65
+ describe Actions::Update, "#save" do
66
+ it "performs a patch with the resource's changed data" do
67
+ widget = Widget.new(:id => 123, :size => "Medium", :quantity => 5)
68
+ widget.size = "Large"
69
+ expect(Printfection).to receive(:patch).
70
+ with("/widgets/123", {"size" => "Large"})
71
+ widget.save
72
+ end
73
+ end
74
+
75
+ describe Actions::Delete, "#delete" do
76
+ it "performs a delete on the resource" do
77
+ widget = Widget.new(:id => 123)
78
+ expect(Printfection).to receive(:delete).with("/widgets/123")
79
+ widget.delete
80
+ end
81
+ end
82
+ end
83
+
data/spec/api_spec.rb ADDED
@@ -0,0 +1,224 @@
1
+ require 'printfection'
2
+
3
+ module Printfection
4
+ describe API, ".api_token=" do
5
+ let(:client) { Object.new.extend(API) }
6
+
7
+ it "sets the api token" do
8
+ client.api_token = "MY-API-TOKEN"
9
+ expect(client.api_token).to eql "MY-API-TOKEN"
10
+ end
11
+ end
12
+
13
+ describe API, "#get" do
14
+ let(:client) { Object.new.extend(API) }
15
+
16
+ before do
17
+ client.api_token = "MY-API-TOKEN"
18
+ end
19
+
20
+ it "returns the response data of a GET request" do
21
+ response_data = double
22
+ expect(client).to receive(:request).
23
+ with(:get, "/path/to/resource/123", {page: 5}).
24
+ and_return(response_data)
25
+ expect(client.get("/path/to/resource/123", page: 5)).to eql response_data
26
+ end
27
+ end
28
+
29
+ describe API, "#post" do
30
+ let(:client) { Object.new.extend(API) }
31
+
32
+ before do
33
+ client.api_token = "MY-API-TOKEN"
34
+ end
35
+
36
+ it "returns the response data of a POST request" do
37
+ response_data = double
38
+ expect(client).to receive(:request).
39
+ with(:post, "/path/to/resource/123", {page: 5}).
40
+ and_return(response_data)
41
+ expect(client.post("/path/to/resource/123", page: 5)).to eql response_data
42
+ end
43
+ end
44
+
45
+ describe API, "#patch" do
46
+ let(:client) { Object.new.extend(API) }
47
+
48
+ before do
49
+ client.api_token = "MY-API-TOKEN"
50
+ end
51
+
52
+ it "returns the response data of a PATCH request" do
53
+ response_data = double
54
+ expect(client).to receive(:request).
55
+ with(:patch, "/path/to/resource/123", {page: 5}).
56
+ and_return(response_data)
57
+ expect(client.patch("/path/to/resource/123", page: 5)).to eql response_data
58
+ end
59
+ end
60
+
61
+ describe API, "#delete" do
62
+ let(:client) { Object.new.extend(API) }
63
+
64
+ before do
65
+ client.api_token = "MY-API-TOKEN"
66
+ end
67
+
68
+ it "returns the response data of a DELETE request" do
69
+ response_data = double
70
+ expect(client).to receive(:request).
71
+ with(:delete, "/path/to/resource/123").
72
+ and_return(response_data)
73
+ expect(client.delete("/path/to/resource/123")).to eql response_data
74
+ end
75
+ end
76
+
77
+ describe API, "#request" do
78
+ let(:client) { Object.new.extend(API) }
79
+
80
+ before do
81
+ client.api_token = "MY-API-TOKEN"
82
+ end
83
+
84
+ context "when it is a GET request" do
85
+ it "performs a get with the params" do
86
+ expect(RestClient).to receive(:get).
87
+ with("https://MY-API-TOKEN:@api.printfection.com/v2/path/to/resource/123", {:params => {:page => 5}, :accept => :json}).
88
+ and_return(double(:body => "{}"))
89
+ client.request(:get, "/path/to/resource/123", page: 5)
90
+ end
91
+ end
92
+
93
+ context "when it is a POST request" do
94
+ it "performs a post with the params" do
95
+ expect(RestClient).to receive(:post).
96
+ with("https://MY-API-TOKEN:@api.printfection.com/v2/path/to/resource/123", {page: 5}.to_json, {:accept => :json, :content_type => :json}).
97
+ and_return(double(:body => "{}"))
98
+ client.request(:post, "/path/to/resource/123", {page: 5})
99
+ end
100
+ end
101
+
102
+ context "when it is a PATCH request" do
103
+ it "performs a patch with the params" do
104
+ expect(RestClient).to receive(:patch).
105
+ with("https://MY-API-TOKEN:@api.printfection.com/v2/path/to/resource/123", {page: 5}.to_json, {:accept => :json, :content_type => :json}).
106
+ and_return(double(:body => "{}"))
107
+ client.request(:patch, "/path/to/resource/123", {page: 5})
108
+ end
109
+ end
110
+
111
+ context "when it is a DELETE request" do
112
+ it "performs a delete on the uri" do
113
+ expect(RestClient).to receive(:delete).
114
+ with("https://MY-API-TOKEN:@api.printfection.com/v2/path/to/resource/123").
115
+ and_return(double(:body => "{}"))
116
+ client.request(:delete, "/path/to/resource/123")
117
+ end
118
+ end
119
+
120
+ context "when it is successful" do
121
+ let(:raw_json) { double(:raw_json) }
122
+ let(:response) { double(:response, :body => raw_json) }
123
+ let(:parsed_json) { double(:parsed_json).as_null_object }
124
+
125
+ before do
126
+ allow(RestClient).to receive(:get).
127
+ with("https://MY-API-TOKEN:@api.printfection.com/v2/path/to/resource/123", {:params => {:page => 5}, :accept => :json}).
128
+ and_return(response)
129
+ end
130
+
131
+ context "when it can be parsed" do
132
+ before do
133
+ allow(JSON).to receive(:parse).
134
+ with(raw_json).
135
+ and_return(parsed_json)
136
+ end
137
+
138
+ it "returns the parsed JSON" do
139
+ json = client.request(:get, "/path/to/resource/123", page: 5)
140
+ expect(json).to eql parsed_json
141
+ end
142
+ end
143
+
144
+ context "when it is a list object" do
145
+ let(:list_element1) { double }
146
+ let(:list_element2) { double }
147
+
148
+ let(:parsed_json_list_object) do
149
+ {
150
+ "object" => "list",
151
+ "data" => [
152
+ list_element1,
153
+ list_element2
154
+ ]
155
+ }
156
+ end
157
+
158
+ before do
159
+ allow(JSON).to receive(:parse).
160
+ with(raw_json).
161
+ and_return(parsed_json_list_object)
162
+ end
163
+
164
+ it "returns the data property from the parsed json" do
165
+ json = client.request(:get, "/path/to/resource/123", page: 5)
166
+ expect(json).to eql [list_element1, list_element2]
167
+ end
168
+ end
169
+
170
+ context "when it cannot be parsed" do
171
+ before do
172
+ allow(JSON).to receive(:parse).
173
+ with(raw_json).
174
+ and_raise(JSON::ParserError)
175
+ end
176
+
177
+ it "raises Error" do
178
+ expect {
179
+ client.request(:get, "/path/to/resource/123", page: 5)
180
+ }.to raise_error Printfection::Error
181
+ end
182
+ end
183
+ end
184
+
185
+ context "when it is not successful" do
186
+ context "when it is a known http status code" do
187
+ it "raises an Error with the appropriate message" do
188
+ response = double(:response, code: 400, body: '{"message":"Invalid or missing request parameters."}')
189
+ allow(RestClient).to receive(:get).and_raise(RestClient::Exception.new(response))
190
+ expect { client.request(:get, "/path/to/resource/123") }.to raise_error Printfection::Error, "Invalid or missing request parameters."
191
+
192
+ response = double(:response, code: 401, body: '{"message":"Invalid API key provided."}')
193
+ allow(RestClient).to receive(:get).and_raise(RestClient::Exception.new(response))
194
+ expect { client.request(:get, "/path/to/resource/123") }.to raise_error Printfection::Error, "Invalid API key provided."
195
+
196
+ response = double(:response, code: 404, body: '{"message":"Not Found."}')
197
+ allow(RestClient).to receive(:get).and_raise(RestClient::Exception.new(response))
198
+ expect { client.request(:get, "/path/to/resource/123") }.to raise_error Printfection::Error, "Not Found."
199
+ end
200
+ end
201
+
202
+ context "when it is an unknown http status code" do
203
+ it "raises an Error with a generic message" do
204
+ allow(RestClient).to receive(:get).
205
+ and_raise(RestClient::Exception)
206
+ expect {
207
+ client.request(:get, "/path/to/resource/123")
208
+ }.to raise_error Printfection::Error, "Something went wrong with the request. Please try again."
209
+ end
210
+ end
211
+
212
+ context "when an unknown exception is raised" do
213
+ it "raises an Error with a generic message" do
214
+ allow(RestClient).to receive(:get).
215
+ and_raise(StandardError)
216
+ expect {
217
+ client.request(:get, "/path/to/resource/123")
218
+ }.to raise_error Printfection::Error, "Something went wrong. Please try again."
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
224
+
@@ -0,0 +1,30 @@
1
+ require 'printfection'
2
+
3
+ module Printfection
4
+ describe Asset, "properties" do
5
+ let(:json) do
6
+ JSON.parse <<-JSON
7
+ {
8
+ "id": 1,
9
+ "object": "asset",
10
+ "type": "display",
11
+ "name": "AA-WhiteLogo-Front.png",
12
+ "perspective": "front",
13
+ "url": "https://img.printfection.com/18/26/234234lkajsdfdsf7/AA-WhiteLogo-Front.png",
14
+ "notes": ""
15
+ }
16
+ JSON
17
+ end
18
+
19
+ it "gives access to JSON properties" do
20
+ asset = Asset.new(json)
21
+ expect(asset.id).to eql 1
22
+ expect(asset.type).to eql "display"
23
+ expect(asset.name).to eql "AA-WhiteLogo-Front.png"
24
+ expect(asset.perspective).to eql "front"
25
+ expect(asset.url).to eql "https://img.printfection.com/18/26/234234lkajsdfdsf7/AA-WhiteLogo-Front.png"
26
+ expect(asset.notes).to eql ""
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,44 @@
1
+ require 'printfection'
2
+
3
+ module Printfection
4
+ describe Campaign do
5
+ it_behaves_like "Resource"
6
+ include_examples "Actions::Retrieve"
7
+ include_examples "Actions::List"
8
+ end
9
+
10
+ describe Campaign, ".uri" do
11
+ it "returns the base resource uri" do
12
+ expect(Campaign.uri).to eql "/campaigns"
13
+ end
14
+ end
15
+
16
+ describe Campaign, "properties" do
17
+ let(:json) do
18
+ JSON.parse <<-JSON
19
+ {
20
+ "id": 1,
21
+ "object": "campaign",
22
+ "type": "giveaway",
23
+ "name": "My Awesome Giveaway Campaign",
24
+ "active": true,
25
+ "archived": false,
26
+ "url": "https://get.printfection.com/i8kbn/6651657281",
27
+ "created_at": "2014-09-12T10:22:37Z"
28
+ }
29
+ JSON
30
+ end
31
+
32
+ it "gives access to JSON properties" do
33
+ campaign = Campaign.new(json)
34
+ expect(campaign.id).to eql 1
35
+ expect(campaign.type).to eql "giveaway"
36
+ expect(campaign.name).to eql "My Awesome Giveaway Campaign"
37
+ expect(campaign.active).to eql true
38
+ expect(campaign.archived).to eql false
39
+ expect(campaign.url).to eql "https://get.printfection.com/i8kbn/6651657281"
40
+ expect(campaign.created_at).to eql DateTime.parse("2014-09-12T10:22:37Z")
41
+ end
42
+ end
43
+ end
44
+
data/spec/item_spec.rb ADDED
@@ -0,0 +1,118 @@
1
+ require 'printfection'
2
+
3
+ module Printfection
4
+ describe Item do
5
+ it_behaves_like "Resource"
6
+ include_examples "Actions::Retrieve"
7
+ include_examples "Actions::List"
8
+ end
9
+
10
+ describe Item, ".uri" do
11
+ it "returns the base resource uri" do
12
+ expect(Item.uri).to eql "/items"
13
+ end
14
+ end
15
+
16
+ describe Item, "properties" do
17
+ let(:json) do
18
+ JSON.parse <<-JSON
19
+ {
20
+ "id": 1,
21
+ "object": "item",
22
+ "name": "My Awesome T-Shirt",
23
+ "color": "Green",
24
+ "product": {
25
+ "id": 123,
26
+ "name": "American Apparel 50/50 T-Shirt"
27
+ },
28
+ "created_at": "2014-09-12T10:22:37Z",
29
+ "campaigns": [
30
+ {
31
+ "id": 1,
32
+ "object": "campaign",
33
+ "type": "giveaway",
34
+ "name": "My Awesome Giveaway Campaign",
35
+ "active": true,
36
+ "archived": false,
37
+ "url": "https://get.printfection.com/i8kbn/6651657281",
38
+ "created_at": "2014-09-12T10:22:37Z"
39
+ },
40
+ {
41
+ "id": 2,
42
+ "object": "campaign",
43
+ "type": "giveaway",
44
+ "name": "My Other Giveaway Campaign",
45
+ "active": false,
46
+ "archived": true,
47
+ "url": "https://get.printfection.com/i8kbn/6651657282",
48
+ "created_at": "2014-09-11T10:22:37Z"
49
+ }
50
+ ],
51
+ "sizes": [
52
+ {
53
+ "id": 1,
54
+ "object": "size",
55
+ "name": "Medium",
56
+ "short_name": "M",
57
+ "stock": {
58
+ "available": 498
59
+ }
60
+ },
61
+ {
62
+ "id": 2,
63
+ "object": "size",
64
+ "name": "Large",
65
+ "short_name": "L",
66
+ "stock": {
67
+ "available": 996
68
+ }
69
+ }
70
+ ],
71
+ "assets": [
72
+ {
73
+ "id": 1,
74
+ "object": "asset",
75
+ "type": "display",
76
+ "name": "AA-WhiteLogo-Front.png",
77
+ "perspective": "front",
78
+ "url": "https://img.printfection.com/18/26/234234lkajsdfdsf7/AA-WhiteLogo-Front.png",
79
+ "notes": ""
80
+ },
81
+ {
82
+ "id": 2,
83
+ "object": "asset",
84
+ "type": "display",
85
+ "name": "AA-WhiteLogo-Back.png",
86
+ "perspective": "back",
87
+ "url": "https://img.printfection.com/18/26/234234lkajsdfdsf7/AA-WhiteLogo-Back.png",
88
+ "notes": ""
89
+ }
90
+ ]
91
+ }
92
+ JSON
93
+ end
94
+
95
+ it "gives access to JSON properties" do
96
+ item = Item.new(json)
97
+ expect(item.id).to eql 1
98
+ expect(item.name).to eql "My Awesome T-Shirt"
99
+ expect(item.color).to eql "Green"
100
+ expect(item.created_at).to eql DateTime.parse("2014-09-12T10:22:37Z")
101
+
102
+ expect(item.product).to be_a Product
103
+
104
+ expect(item.campaigns).to be_an Array
105
+ expect(item.campaigns.count).to eql 2
106
+ expect(item.campaigns.first).to be_a Campaign
107
+
108
+ expect(item.sizes).to be_an Array
109
+ expect(item.sizes.count).to eql 2
110
+ expect(item.sizes.first).to be_a Size
111
+
112
+ expect(item.assets).to be_an Array
113
+ expect(item.assets.count).to eql 2
114
+ expect(item.assets.first).to be_a Asset
115
+ end
116
+ end
117
+ end
118
+