shipping_materials 0.0.1

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,27 @@
1
+ module ShippingMaterials
2
+ class Group
3
+ include Sortable
4
+
5
+ attr_accessor :objects, :basename, :csvs
6
+
7
+ def initialize(basename, objects)
8
+ @basename = basename
9
+ @objects = objects
10
+ @csvs = []
11
+ @extension = 'csv'
12
+ @headers = false
13
+ end
14
+
15
+ def filter(&block)
16
+ @objects = @objects.select {|o| o.instance_eval(&block) }
17
+ end
18
+
19
+ def csv(options={}, &block)
20
+ if block
21
+ csv = CSVDSL.new(@objects, options)
22
+ csv.instance_eval(&block)
23
+ @csvs << csv
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ module ShippingMaterials
2
+ module Sortable
3
+ attr_accessor :sorters
4
+
5
+ # DSL method
6
+ def sort(context=:objects, &block)
7
+ @sorters ||= {}
8
+ @sorters[context] = Sorter.new
9
+ @sorters[context].instance_eval(&block)
10
+ end
11
+
12
+ # Perform the sort
13
+ def sort!
14
+ @sorters.each do |context, sorter|
15
+ @objects = if context == :objects
16
+ sorter.sort(@objects)
17
+ else
18
+ @objects.each do |object|
19
+ object.send(:"#{context}=", sorter.sort(object.send(context)))
20
+ end
21
+ end
22
+ end
23
+ @objects
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,52 @@
1
+ module ShippingMaterials
2
+ class Packager
3
+ include Sortable
4
+
5
+ attr_accessor :objects, :groups, :template
6
+
7
+ def initialize
8
+ @groups = []
9
+ end
10
+
11
+ def package(objects, &block)
12
+ @objects = objects
13
+ instance_eval(&block)
14
+ @groups.each do |group|
15
+ sort_group(group)
16
+ create_packing_slips(group)
17
+ csvs(group)
18
+ end
19
+ Storage.gzip if Config.use_gzip?
20
+ end
21
+
22
+ def pdf(template)
23
+ @packing_slip_template = template
24
+ end
25
+
26
+ def group(basename, &block)
27
+ group = Group.new(basename, @objects)
28
+ group.instance_eval(&block) if block
29
+ @groups << group
30
+ end
31
+
32
+ private
33
+
34
+ def sort_group(group)
35
+ return unless self.sorters.nil?
36
+ group.sorters ||= self.sorters unless group.sorters.nil?
37
+ group.sort!
38
+ end
39
+
40
+ def create_packing_slips(group)
41
+ packing_slip = PackingSlips.new(group.objects, @packing_slip_template)
42
+ Storage.write_pdf(group.basename, packing_slip.to_s)
43
+ end
44
+
45
+ def csvs(group)
46
+ group.csvs.each do |csv|
47
+ extension = group.basename + '.' + csv.extension
48
+ Storage.write_file(extension, csv.to_s)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,17 @@
1
+ module ShippingMaterials
2
+ class PackingSlips
3
+ def initialize(objects, template_file)
4
+ @objects = objects
5
+ @template_file = template_file
6
+ end
7
+
8
+ def to_s
9
+ t = Mustache.new
10
+ t.template_file = @template_file
11
+ t[Config.base_context] = @objects
12
+ t.render
13
+ end
14
+
15
+ alias_method :to_html, :to_s
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ module ShippingMaterials
2
+ class S3
3
+ begin
4
+ require 'aws-sdk'
5
+ rescue LoadError => e
6
+ e.message << " (You may need to install the aws-sdk gem)"
7
+ raise e
8
+ end unless defined?(::AWS::Core)
9
+
10
+ def initialize
11
+ @bucket = self.s3.buckets[Config.s3_bucket]
12
+ end
13
+
14
+ def write(key, fp)
15
+ @bucket.objects.create(key, fp)
16
+ end
17
+
18
+ def s3
19
+ @s3 ||= AWS::S3.new(access_key_id: Config.s3_access_key,
20
+ secret_access_ket: Config.s3_secret)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,49 @@
1
+ module ShippingMaterials
2
+ class Sorter
3
+ def initialize
4
+ @rules = []
5
+ @attr_callbacks = []
6
+ end
7
+
8
+ def rule(&block)
9
+ @rules << block
10
+ end
11
+
12
+ # This is suiting MY purpose for now
13
+ # The plan is to implement chainable callbacks
14
+ def each_by(attr)
15
+ @attr_callbacks << attr
16
+ end
17
+
18
+ def sort(items, i=0)
19
+ return items if !@rules[i] || items.size < 2
20
+
21
+ a, b = [], []
22
+
23
+ items.each do |item|
24
+ if item.instance_eval(&@rules[i])
25
+ a << item
26
+ else
27
+ b << item
28
+ end
29
+ end
30
+
31
+ apply_callbacks(a)
32
+ apply_callbacks(b)
33
+
34
+ i += 1
35
+ ( sort(a, i) + sort(b, i) ).compact
36
+ end
37
+
38
+
39
+ private
40
+
41
+ def apply_callbacks(items)
42
+ @attr_callbacks.each do |attr|
43
+ items.sort! do |a,b|
44
+ b.send(attr) <=> a.send(attr)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,54 @@
1
+ module ShippingMaterials
2
+ class Storage
3
+ class << self
4
+ def write_file(filename, contents)
5
+ filename = "#{save_path}/#{filename}"
6
+ File.open(filename, 'w') do |fp|
7
+ fp.write(contents)
8
+ if Config.use_s3? && !Config.use_gzip?
9
+ @s3 ||= S3.new
10
+ @s3.write(filename, fp)
11
+ File.unlink(fp)
12
+ end
13
+ end
14
+ end
15
+
16
+ def write_pdf(filename, contents)
17
+ basename = filenameize(File.basename(filename, '.*'))
18
+ base = "#{save_path}/#{basename}"
19
+ html_file, pdf_file = base + '.html', base + '.pdf'
20
+ File.open(html_file, 'w') {|f| f.write(contents) }
21
+ %x( wkhtmltopdf #{html_file} #{pdf_file} )
22
+ File.unlink(html_file)
23
+ if Config.use_s3? && !Config.use_gzip?
24
+ @s3 ||= S3.new
25
+ File.open(pdf_file) do |fp|
26
+ @s3.write(File.basename(pdf_file), fp)
27
+ end
28
+ File.unlink(pdf_file)
29
+ end
30
+ end
31
+
32
+ def gzip
33
+ filename = "#{Config.save_path}/#{Config.gzip_file_name}"
34
+ `cd #{Config.save_path} && tar -cvzf #{filename} * && cd -`
35
+ if Config.use_s3?
36
+ @s3 ||= S3.new
37
+ File.open(filename) do |fp|
38
+ @s3.write(Config.gzip_file_name, fp)
39
+ end
40
+ FileUtils.rm_rf(self.save_path) unless self.save_path == '/'
41
+ end
42
+ end
43
+
44
+ def save_path
45
+ FileUtils.mkdir(Config.save_path) unless Dir.exists?(Config.save_path)
46
+ Config.save_path
47
+ end
48
+
49
+ def filenameize(string)
50
+ string.gsub(/[^A-Z0-9_]+/i, '')
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,3 @@
1
+ module ShippingMaterials
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'shipping_materials/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'shipping_materials'
8
+ spec.version = ShippingMaterials::VERSION
9
+ spec.authors = ['Andrew Haust']
10
+ spec.email = ['andrewwhhaust@gmail.com']
11
+ spec.description = %q{DSL for creating packing slips
12
+ and general shipping materials}
13
+ spec.summary = %q{Shipping Materials}
14
+ spec.homepage = "http://www.github.com/sodapopcan/shipping_materials"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split("\n")
18
+ spec.executables = spec.files.grep(%r{^bin/}) {|f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'mustache'
23
+ spec.add_dependency 'aws-sdk'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.3'
26
+ spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'debugger'
28
+ end
data/test/data.rb ADDED
@@ -0,0 +1,217 @@
1
+ require File.expand_path('../models', __FILE__)
2
+
3
+ module TestData
4
+
5
+ def orders
6
+ @orders ||= get_orders
7
+ end
8
+
9
+ def get_orders
10
+ orders = []
11
+
12
+ o = TestModels::Order.new
13
+ o.id = 1
14
+ o.name = 'Andrew'
15
+ o.address = '207 Lawrence Ave E'
16
+ o.email = 'andrew@gelaskins.com'
17
+ o.phone = '416-555-0634'
18
+ o.country = 'CA'
19
+ o.shipping_method = 'UPS'
20
+
21
+ li = TestModels::LineItem.new
22
+ li.id = 1
23
+ li.name = 'Plague Soundscapes'
24
+ li.type = 'Vinyl'
25
+ li.quantity = 3
26
+ li.price = 15.95
27
+ li.variant = TestModels::Variant.new(name: 'plague soundscapes')
28
+ o.line_items << li
29
+
30
+ li = TestModels::LineItem.new
31
+ li.id = 2
32
+ li.name = 'Surfer Rosa'
33
+ li.type = 'Vinyl'
34
+ li.quantity = 1
35
+ li.price = 37.24
36
+ li.variant = TestModels::Variant.new(name: 'surfer rosa')
37
+ o.line_items << li
38
+
39
+ orders << o
40
+
41
+
42
+ o = TestModels::Order.new
43
+ o.id = 2
44
+ o.name = 'Julie'
45
+ o.address = '17 Whatever St'
46
+ o.email = 'julie@email.com'
47
+ o.phone = '232-555-0001'
48
+ o.country = 'US'
49
+ o.shipping_method = 'std'
50
+
51
+ li = TestModels::LineItem.new
52
+ li.id = 3
53
+ li.name = 'Analphabetapolothology'
54
+ li.type = 'Vinyl'
55
+ li.quantity = 1
56
+ li.price = 20.45
57
+ o.line_items << li
58
+
59
+ orders << o
60
+
61
+
62
+ o = TestModels::Order.new
63
+ o.id = 3
64
+ o.name = 'Derek'
65
+ o.address = '17 Whatever St'
66
+ o.email = 'derek@email.com'
67
+ o.phone = '232-555-0001'
68
+ o.country = 'US'
69
+ o.shipping_method = 'std'
70
+
71
+ li = TestModels::LineItem.new
72
+ li.id = 4
73
+ li.name = 'The Immaculate Collection'
74
+ li.type = 'Vinyl'
75
+ li.quantity = 3
76
+ li.price = 20
77
+ o.line_items << li
78
+
79
+ li = TestModels::LineItem.new
80
+ li.id = 9
81
+ li.name = '()'
82
+ li.type = 'CD'
83
+ li.quantity = 2
84
+ li.price = 20
85
+ o.line_items << li
86
+
87
+ li = TestModels::LineItem.new
88
+ li.id = 10
89
+ li.name = 'Siamese Dream'
90
+ li.type = 'CD'
91
+ li.quantity = 5
92
+ li.price = 20
93
+ o.line_items << li
94
+
95
+ li = TestModels::LineItem.new
96
+ li.id = 11
97
+ li.name = 'Parklife'
98
+ li.type = 'CD'
99
+ li.quantity = 1
100
+ li.price = 20
101
+ o.line_items << li
102
+
103
+ li = TestModels::LineItem.new
104
+ li.id = 12
105
+ li.name = 'The Eldrich Dark'
106
+ li.type = 'Vinyl'
107
+ li.quantity = 1
108
+ li.price = 20
109
+ o.line_items << li
110
+
111
+ li = TestModels::LineItem.new
112
+ li.id = 13
113
+ li.name = 'Totally Krossed Out'
114
+ li.type = 'Cassette'
115
+ li.quantity = 1
116
+ li.price = 8
117
+ o.line_items << li
118
+
119
+ li = TestModels::LineItem.new
120
+ li.id = 14
121
+ li.name = 'Schubert Dip'
122
+ li.type = 'Cassette'
123
+ li.quantity = 1
124
+ li.price = 12
125
+ o.line_items << li
126
+
127
+ li = TestModels::LineItem.new
128
+ li.id = 15
129
+ li.name = 'Please Hammer, Don\'t Hurt \'Em'
130
+ li.type = 'CD'
131
+ li.quantity = 10
132
+ li.price = 12
133
+ o.line_items << li
134
+
135
+ orders << o
136
+
137
+
138
+ o = TestModels::Order.new
139
+ o.id = 4
140
+ o.name = 'Riley'
141
+ o.address = '17 Whatever St'
142
+ o.email = 'riley@email.com'
143
+ o.phone = '416-555-0987'
144
+ o.country = 'CA'
145
+ o.shipping_method = 'UPSexp'
146
+
147
+ li = TestModels::LineItem.new
148
+ li.id = 5
149
+ li.name = 'Don Caballero 2'
150
+ li.type = 'CD'
151
+ li.quantity = 1
152
+ li.price = 12
153
+ o.line_items << li
154
+
155
+ orders << o
156
+
157
+
158
+ o = TestModels::Order.new
159
+ o.id = 4
160
+ o.name = 'Miller'
161
+ o.address = '17 Whatever St'
162
+ o.email = 'miller@email.com'
163
+ o.phone = '416-555-0987'
164
+ o.country = 'CA'
165
+ o.shipping_method = 'UPSexp'
166
+
167
+ li = TestModels::LineItem.new
168
+ li.id = 6
169
+ li.name = 'Confield'
170
+ li.type = 'CD'
171
+ li.quantity = 1
172
+ li.price = 12
173
+ o.line_items << li
174
+
175
+ orders << o
176
+
177
+
178
+ o = TestModels::Order.new
179
+ o.id = 5
180
+ o.name = 'Jan'
181
+ o.address = '45 Bergen Strasse'
182
+ o.email = 'jan@email.com'
183
+ o.phone = '876-555-0987'
184
+ o.country = 'DE'
185
+ o.shipping_method = 'UPSexp'
186
+
187
+ li = TestModels::LineItem.new
188
+ li.id = 7
189
+ li.name = 'Living with the Ancients'
190
+ li.type = 'Vinyl'
191
+ li.quantity = 1
192
+ li.price = 12
193
+ o.line_items << li
194
+
195
+ orders << o
196
+
197
+
198
+ o = TestModels::Order.new
199
+ o.id = 6
200
+ o.name = 'J.M.'
201
+ o.address = '1233 St. Clair Ave W'
202
+ o.email = 'jm@email.com'
203
+ o.phone = '876-555-0987'
204
+ o.country = 'CA'
205
+ o.shipping_method = 'std'
206
+
207
+ li = TestModels::LineItem.new
208
+ li.id = 8
209
+ li.name = 'Vistavision'
210
+ li.type = 'Vinyl'
211
+ li.quantity = 5
212
+ li.price = 12
213
+ o.line_items << li
214
+
215
+ orders << o
216
+ end
217
+ end