thousand_island 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 389fb55f938dbc9612ecbdab028eb4c6f7a1ba6b
4
+ data.tar.gz: ef8e4cb13f7628a49c8f61af335686b6bf9596e6
5
+ SHA512:
6
+ metadata.gz: a720ae6858b1a2716f90b110aa5686023302add7de08f1e0929ca1e0da7b98877ac1c8d58dd6d10c7e0ea07530da3a3c5798fd9359dc64d9863e9bd2a9ba17a5
7
+ data.tar.gz: 12528531c5d4239969608d7ca0e0d6480494d84234293515a3ac587e16996b780ae2cd28fed86d85098209f48e58f1c3d8eed77ad275db5ab3939e0184f25355
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .ruby-gemset
19
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
4
+ - 2.0.0
5
+ - 1.9.3
6
+ script: bundle exec rspec spec
7
+ env:
8
+ global:
9
+ secure: eswj1U2HJcBv8pIbk8TkBiry8GXQvFhIqaz/XYkvAC5pPDJrzTK9GpSjo2AkvRgck+H99ukzNmwd6Sn1cnnTE/9lsbSogXvBj588KOxivlQ03bZay2g0aeL35qtSnhmJ1e7G4+B3GRyqEYxHboIOKaKBNP93d9+0VVgmm+wfPPw=
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in thousand_island.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,23 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ # Note: The cmd option is now required due to the increasing number of ways
5
+ # rspec may be run, below are examples of the most common uses.
6
+ # * bundler: 'bundle exec rspec'
7
+ # * bundler binstubs: 'bin/rspec'
8
+ # * spring: 'bin/rsspec' (This will use spring if running and you have
9
+ # installed the spring binstubs per the docs)
10
+ # * zeus: 'zeus rspec' (requires the server to be started separetly)
11
+ # * 'just' rspec: 'rspec'
12
+ guard :rspec, cmd: 'bundle exec rspec -f doc' do
13
+ watch(%r{^spec/.+_spec\.rb$})
14
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
15
+ watch(%r{^lib/thousand_island/(.+)\.rb$}) { |m| "spec/thousand_island/#{m[1]}_spec.rb" }
16
+ watch(%r{^lib/thousand_island/utilities/(.+)\.rb$}) { |m| "spec/thousand_island/utilities/#{m[1]}_spec.rb" }
17
+ watch('spec/spec_helper.rb') { "spec" }
18
+
19
+ # Turnip features and steps
20
+ # watch(%r{^spec/acceptance/(.+)\.feature$})
21
+ # watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
22
+ end
23
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Colin Weight
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,363 @@
1
+ # Thousand Island
2
+ ### Dressing for Prawn
3
+
4
+ [![GitHub version](https://badge.fury.io/gh/colinweight%2Fthousand_island.svg)](http://badge.fury.io/gh/colinweight%2Fthousand_island) [![Code Climate](https://codeclimate.com/github/colinweight/thousand_island/badges/gpa.svg)](https://codeclimate.com/github/colinweight/thousand_island) [![Test Coverage](https://codeclimate.com/github/colinweight/thousand_island/badges/coverage.svg)](https://codeclimate.com/github/colinweight/thousand_island) [![Build Status](https://travis-ci.org/colinweight/thousand_island.svg?branch=master)](https://travis-ci.org/colinweight/thousand_island) [![Inline docs](http://inch-ci.org/github/colinweight/thousand_island.png?branch=master)](http://inch-ci.org/github/colinweight/thousand_island)
5
+
6
+
7
+ [Prawn](https://github.com/prawnpdf/prawn) is awesome. It has some amazing functionality, and you can get anything that's in your head onto a PDF document with some Ruby code. For me though, as wonderful as that is, I normally only need a repeating header and footer, and then some text and maybe a table in between them. This is where **Thousand Island** comes in. A few simple commands should get you set up with a template that you can use application wide, and then all you need to worry about is getting the right content into the document.
8
+
9
+ > Note: ThousandIsland is not meant to be a substitute for learning Prawn, you will get more out of it if you do. The excellent [Prawn Manual](http://prawnpdf.org/manual.pdf) is a great place to start.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'thousand_island'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install thousand_island
24
+
25
+ ## Usage
26
+
27
+ ThousandIsland uses the following classes to get the job done:
28
+
29
+ **ThousandIsland::Template** - The common layout and formatting for your pdfs live in here
30
+
31
+ **ThousandIsland::Builder** - Subclass the Builder for your actual business logic for the pdf itself
32
+
33
+ **ThousandIsland::StyleSheet** - A mixin for defining common styles to be used by your Template
34
+
35
+ A suggested directory structure for a Rails app is as follows, but it's entirely up to you:
36
+
37
+ ```
38
+ app/
39
+ └── pdf_builders/
40
+ ├── my_builder.rb
41
+ └── templates/
42
+ ├── my_template.rb
43
+ ├── my_style_sheet.rb
44
+ ```
45
+ For a non-Rails application, the `lib` directory can be used instead of the `app` directory, but it's all up to you.
46
+
47
+ ### Creating a Template
48
+
49
+ The Template class is where you can define elements that may be common to all (or some) documents within your application. It is likely that a common style will be required, so defining it in a Template and then using that Template subclass in any custom Builders DRYs up your pdf generation, as well as allowing for easy restyling across the whole application.
50
+
51
+ Typically, the Template subclass would define the settings for the Prawn Document, as well as the settings for the header and footer. Add your own or override any existing settings in the `settings` method. Any options passed into the constructor as a Hash will be merged with these settings, and the defaults.
52
+
53
+ Content for the header and footer will be defined in the methods `header_content` and `footer_content`. These methods are passed as a block when the pdf is rendered. Any standard Prawn methods may be used (including bounding boxes or any other layout tools). In addition, any of the styles from the `StyleSheet` can be applied as helper methods. For instance, the default style sheet has a `h1_style` method that returns a ThousandIsland::StyleHash, so in your code you can use:
54
+ ```ruby
55
+ h1 "My Document Header"
56
+ ```
57
+ and Prawn will render the text in the style set in the `h1_style` ThousandIsland::StyleHash.
58
+ In addition to the supplied style methods, you can create a custom method:
59
+ ```ruby
60
+ def magic_style
61
+ ThousandIsland::StyleHash.new({
62
+ size: 15
63
+ style: bold
64
+ })
65
+ end
66
+ ```
67
+ As long as the method ends in the word "_style" and returns a Hash, you magically get to do this:
68
+
69
+ ```ruby
70
+ magic "My magic text is bold and size 15!!"
71
+ ```
72
+
73
+ The method may return a standard Hash, but it is safer to return a ThousandIsland::StyleHash, as this dynamically duplicates a few keys to accommodate using the style in normal Prawn text methods as well as formatted text boxes, which use a slightly different convention. You don't have to worry about that if you use the ThousandIsland::StyleHash.
74
+
75
+ Alternatively, your method could do this:
76
+ ```ruby
77
+ def magic_style
78
+ h1_style.merge({
79
+ size: 15
80
+ style: bold
81
+ })
82
+ end
83
+ ```
84
+ The following is an example of a custom template that subclasses
85
+ ThousandIsland::Template -
86
+ ```ruby
87
+ class MyTemplate < ThousandIsland::Template
88
+ include MyCustomStyleSheet # optional
89
+
90
+ # settings here are merged with and override the defaults
91
+ def settings
92
+ {
93
+ header: {
94
+ height: 55,
95
+ render:true,
96
+ repeated: true
97
+ },
98
+ footer: {
99
+ render:true,
100
+ height: 9,
101
+ numbering_string: 'Page <page> of <total>',
102
+ repeated: true
103
+ }
104
+ }
105
+ end
106
+
107
+ def header_content
108
+ # Standard Prawn syntax
109
+ pdf.image "#{pdf_images_path}/company_logo.png", height: 30
110
+ end
111
+
112
+ def footer_content
113
+ # Using the magic method we get from the footer_style
114
+ footer "www.mycompanyurl.com"
115
+ end
116
+
117
+ def pdf_images_path
118
+ # How you go about this sort of thing is entirely up to you
119
+ "#{Rails.root}/app/assets/pdf_images"
120
+ end
121
+ end
122
+ ```
123
+ >Note: The Footer is a three column layout, with the numbering on the right column and the content defined here in the middle. More flexibility will be added in a later version.
124
+
125
+ Optional:
126
+ Add a `body_content` method to add content before whatever the Builder defines in it's method of the same name.
127
+
128
+ ### StyleSheets
129
+
130
+ The StyleSheet is designed to be a mixin to the Template class. It may also be included into other modules to define custom StyleSheets.
131
+
132
+ Methods should return a StyleHash object rather than a vanilla Hash, as it has some customisation to help it work with Prawn. The default_style is used as the starting point for all other styles. For instance, the `default_style[:size]` value is multiplied in the heading styles, so changing the default style size value will have a cascading effect. Check the source for the default values and override as preferred.
133
+
134
+ An example of a custom StyleSheet:
135
+ ```ruby
136
+ module MyStyleSheet
137
+ include ThousandIsland::StyleSheet
138
+
139
+ def default_style
140
+ super.merge({
141
+ size: 12,
142
+ color: '222222'
143
+ })
144
+ end
145
+
146
+ def h1_style
147
+ super.merge({ align: :center })
148
+ end
149
+ end
150
+ ```
151
+
152
+ ### Creating a Builder
153
+
154
+ Your Builder class is where you will put the necessary logic for rendering the final pdf. It's up to you how you get the data into the Builder. It will depend on the complexity. You might just pass an Invoice object (`MyBuilder.new(invoice))`) or you may have a bunch of methods that are called by an external object to get the data where it needs to be.
155
+
156
+ You must declare which Template class you will be using. Failing to do so will raise a `TemplateRequiredError` when you call the build method. Declare the template with the following in the main class body:
157
+ ```ruby
158
+ uses_template MyTemplate
159
+ ```
160
+
161
+ Your Builder can have a `filename` method, which will help a Rails Controller or other class determine the name to use to send the file to the browser or save to the filesystem (or both). Without this method it will have a default name, so you may choose to put the naming logic for your file elsewhere, it's up to you.
162
+
163
+ You must have a `body_content` method that takes no arguments (or the pdf will be empty!). This is the method that is passed around internally in order for Prawn to render what is in the method. You can use raw Prawn syntax, or any of the style magic methods to render to the pdf. You may also call other methods from your `body_content` method, and use Prawn syntax and magic methods in those too.
164
+
165
+ A Builder example might be:
166
+ ```ruby
167
+ class MyBuilder < ThousandIsland::Builder
168
+ uses_template MyTemplate
169
+
170
+ attr_reader :data
171
+
172
+ def initialize(data={})
173
+ @data = data
174
+ # do something with the data...
175
+ end
176
+
177
+ def filename
178
+ "Document#{data.id_number}"
179
+ end
180
+
181
+ def body_content
182
+ # call custom methods, magic methods or call Prawn methods directly:
183
+ h1 'Main Heading'
184
+ display_info
185
+ body 'Main text in here...'
186
+ end
187
+
188
+ # Custom method called by body_content
189
+ def display_info
190
+ body "Written by: #{data.author}"
191
+ pdf.image data.avatar, height: 20
192
+ end
193
+ end
194
+ ```
195
+
196
+ Finally, to get the finished pdf from your Builder, call the `build` method like so:
197
+ ```ruby
198
+ pdf = my_builder.build
199
+ ```
200
+
201
+ Optional:
202
+
203
+ Define a `header_content` method to add content below whatever is defined in the Template. This will be repeated according to the header settings in the Template.
204
+
205
+ Define a `footer_content` method to add content above whatever is defined in the Template. This will be repeated according to the footer settings in the Template.
206
+
207
+ Define a `settings` method that returns a Hash. This will be passed to the Template class and will override any of the Template default settings.
208
+
209
+ #### Using the Builder in a Rails Application
210
+
211
+ Your Controller can look something like this:
212
+
213
+ ```ruby
214
+ def show
215
+ @thing = Thing.find(params[:id])
216
+ respond_to do |format|
217
+ format.html
218
+ format.pdf do
219
+ data = { thing: @thing } # How you structure this is up to you, it's your Class!!
220
+ builder = MyBuilder.new(data)
221
+ send_data builder.build, filename: builder.filename,
222
+ type: "application/pdf",
223
+ disposition: "inline" # Leave blank to render as a download
224
+ end
225
+ end
226
+ end
227
+ ```
228
+
229
+ If your controller for getting the data for a PDF is that simple, then you're pretty lucky. Normally we're going to want a PDF file to render a few things at once, so you might build a service object that formats the data, and use as follows:
230
+
231
+ ```ruby
232
+ def show
233
+ respond_to do |format|
234
+ format.html do
235
+ @thing_for_html_view = Thing.find(params[:id])
236
+ end
237
+ format.pdf do
238
+ # Tell the service object to do it's thing and return the Builder
239
+ builder = ThingPdfServiceObject.new(params)
240
+ send_data builder.build,
241
+ filename: builder.filename,
242
+ type: "application/pdf",
243
+ disposition: "inline" # Leave blank to render as a download
244
+ end
245
+ end
246
+ end
247
+ ```
248
+
249
+ These are only suggestions, as you can probably tell there is nothing tying you down to a particular way of building and delivering the document. You might even want to save it to the file system, or upload to S3. You could override the build method if you wanted to:
250
+ ```ruby
251
+ def build
252
+ pdf = super
253
+ # Save, upload, send or do whatever....
254
+ end
255
+ ```
256
+ However, that kind of logic seems beyond the scope of the Builder, and should proabably be in the consumer of your Builder class, rather than the builder itself.
257
+
258
+ ## Default Styles
259
+ Out of the box, ThousandIsland gives you some generic styles with default values. Override any of the values in your custom Stylesheet, or your Template. Create your own entirely new style in either of those places too, and get the magic method for free.
260
+
261
+ The default styles are:
262
+ ##### body
263
+ ```ruby
264
+ {
265
+ :size => 10, # Inherited from default_style
266
+ :style => :normal, # Inherited from default_style
267
+ :align => :left, # Inherited from default_style
268
+ :leading => 1, # Inherited from default_style
269
+ :inline_format => true, # Inherited from default_style
270
+ :color => "000000" # Inherited from default_style
271
+ }
272
+ ```
273
+ ##### h1
274
+ ```ruby
275
+ {
276
+ :size => 18, # Calcuated as 1.8 * default_style[:size]
277
+ :style => :bold,
278
+ :align => :left, # Inherited from default_style
279
+ :leading => 8,
280
+ :inline_format => true, # Inherited from default_style
281
+ :color => "000000" # Inherited from default_style
282
+ }
283
+ ```
284
+ ##### h2
285
+ ```ruby
286
+ {
287
+ :size => 15, # Calcuated as 1.5 * default_style[:size]
288
+ :style => :bold,
289
+ :align => :left, # Inherited from default_style
290
+ :leading => 4,
291
+ :inline_format => true, # Inherited from default_style
292
+ :color => "000000" # Inherited from default_style
293
+ }
294
+ ```
295
+ ##### h3
296
+ ```ruby
297
+ {
298
+ :size => 14, # Calcuated as 1.4 * default_style[:size]
299
+ :style => :bold,
300
+ :align => :left, # Inherited from default_style
301
+ :leading => 4,
302
+ :inline_format => true, # Inherited from default_style
303
+ :color => "000000" # Inherited from default_style
304
+ }
305
+ ```
306
+ ##### h4
307
+ ```ruby
308
+ {
309
+ :size => 11, # Calcuated as 1.1 * default_style[:size]
310
+ :style => :bold_italic,
311
+ :align => :left, # Inherited from default_style
312
+ :leading => 4,
313
+ :inline_format => true, # Inherited from default_style
314
+ :color => "000000" # Inherited from default_style
315
+ }
316
+ ```
317
+ ##### h5
318
+ ```ruby
319
+ {
320
+ :size => 10, # Calcuated as 1 * default_style[:size]
321
+ :style => :normal, # Inherited from default_style
322
+ :align => :left, # Inherited from default_style
323
+ :leading => 4,
324
+ :inline_format => true, # Inherited from default_style
325
+ :color => "000000" # Inherited from default_style
326
+ }
327
+ ```
328
+ ##### h6
329
+ ```ruby
330
+ {
331
+ :size => 8.5, # Calcuated as 0.85 * default_style[:size]
332
+ :style => :italic,
333
+ :align => :left, # Inherited from default_style
334
+ :leading => 4,
335
+ :inline_format => true, # Inherited from default_style
336
+ :color => "000000" # Inherited from default_style
337
+ }
338
+ ```
339
+ ##### footer
340
+ ```ruby
341
+ {
342
+ :size => 0.8, # Calcuated as 0.8 * default_style[:size]
343
+ :style => :normal,
344
+ :align => :left, # Inherited from default_style
345
+ :leading => 1, # Inherited from default_style
346
+ :inline_format => true, # Inherited from default_style
347
+ :color => "666666"
348
+ }
349
+ ```
350
+
351
+ ## To come...
352
+ - Easy (and repeatable) Table formatting
353
+ - Easy list rendering and styling (including nested lists)
354
+ - More flexibility in the Footer layout
355
+ - (Possibly) Command line functions to create common subclass files
356
+
357
+ ## Contributing
358
+
359
+ 1. Fork it
360
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
361
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
362
+ 4. Push to the branch (`git push origin my-new-feature`)
363
+ 5. Create new Pull Request