thousand_island 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/README.md +156 -52
- data/lib/thousand_island.rb +15 -12
- data/lib/thousand_island/builder.rb +4 -0
- data/lib/thousand_island/components/footer.rb +5 -3
- data/lib/thousand_island/table.rb +119 -0
- data/lib/thousand_island/table_settings.rb +58 -0
- data/lib/thousand_island/template.rb +5 -5
- data/lib/thousand_island/utilities/utilities.rb +68 -36
- data/lib/thousand_island/version.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/thousand_island/builder_spec.rb +6 -4
- data/spec/thousand_island/table_spec.rb +107 -0
- data/spec/thousand_island/template_spec.rb +1 -2
- data/spec/thousand_island/utilities/utilities_spec.rb +117 -55
- data/thousand_island.gemspec +17 -14
- metadata +37 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c954cf1458e611ac4249a9b3a39d8136db0cf14
|
4
|
+
data.tar.gz: 02b295ba89ca8e95219343ef9414ef648752c4d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e616580434d106f2629097376c9b97eb602d07e0cd47bd22ca4e081834d48241d025ac9c75569f6aad7d9e109343c6634a95bdcb0ce65656f34669e19234ce9
|
7
|
+
data.tar.gz: 5a010d76d9bdd237127e6efd91937b218021b41dd358f0aba9b5d2a8aa3c98f4276b50fc56a63187c5dadbc6758ae694f57e29136c9fe9ed8dfd8ed41f62bb12
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Thousand Island
|
2
|
-
|
2
|
+
**Dressing for Prawn**
|
3
3
|
|
4
|
-
[![
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/thousand_island.svg)](http://badge.fury.io/rb/thousand_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
5
|
|
6
6
|
|
7
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.
|
@@ -229,7 +229,7 @@ def show
|
|
229
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
230
|
|
231
231
|
```ruby
|
232
|
-
def show
|
232
|
+
def show
|
233
233
|
respond_to do |format|
|
234
234
|
format.html do
|
235
235
|
@thing_for_html_view = Thing.find(params[:id])
|
@@ -255,6 +255,87 @@ These are only suggestions, as you can probably tell there is nothing tying you
|
|
255
255
|
```
|
256
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
257
|
|
258
|
+
## Tables
|
259
|
+
|
260
|
+
Quite often a pdf will need to render tabular data. It makes sense if there is a common table styling for all PDFs in your application (although it's not compulsory!). Thousand Island has a Table class, and a TableStyle class.
|
261
|
+
|
262
|
+
> Note: **Thousand Island** has been designed to handle the most common scenarios, and therefore cannot cover every possibility and still keep it simple. If there's anything you can't do with a ThousandIsland::Table, you may need to use Prawn's standard table rendering. There's nothing stopping your Builder rendering a table without using any of the Table implementation in **Thousand Island**. Check out the [Prawn Table Manual](http://prawnpdf.org/prawn-table-manual.pdf) for the full capabilities.
|
263
|
+
|
264
|
+
### Creating a Table
|
265
|
+
There are three main components of a table, header body and footer
|
266
|
+
#### Header
|
267
|
+
Header rows are optional. By doing nothing, your table will have no header row/s. To have a header in your table, you have several options:
|
268
|
+
```ruby
|
269
|
+
# Straightforward single row, no builder logic required
|
270
|
+
header_rows = [['Column One', 'Column Two', 'Column Three']]
|
271
|
+
|
272
|
+
# Build gradually (You can use Prawn native syntax for span and formatting)
|
273
|
+
header_rows << [{content: 'First Two Columns', colspan: 2}, 'Third']
|
274
|
+
header_rows << ['Column One', 'Column Two', 'Column Three']
|
275
|
+
|
276
|
+
```
|
277
|
+
|
278
|
+
By default **Thousand Island** takes all the rows in the <code>header_rows</code> and formats them as a repeating header. If you don't want a header, don't put anything in <code>header_rows</code>. If you don't want the header to repeat across pages, then set:
|
279
|
+
```ruby
|
280
|
+
header_repeat: false
|
281
|
+
```
|
282
|
+
in either the <code>settings</code> method (which returns a hash specific to this Table class) or by setting it in you TableSettings custom class.
|
283
|
+
|
284
|
+
#### Body
|
285
|
+
Similar to <code>header_rows</code>, <code>body_rows</code> can be set in one go or build gradually. Given the nature of the content of a table, it is more likely you'll have a method in that iterates through a collection of objects and builds the table according to the requirements.
|
286
|
+
The way you build the Array of nested Array for the body is up to you. Three suggestions:
|
287
|
+
|
288
|
+
- **Simple Data**: Simply set the <code>body_rows</code> as an Array of Arrays anywhere that's convenient
|
289
|
+
- **Slightly Complex**: Iterate over a collection craeting and Array of "cellable" objects for Prawn, and add to <code>body_rows</code> as you go (<code>body_rows << newly_built_row</code>). You can do this in your Builder and pass it to the Table, or pass objects from your Builder to your Table so that the Table can deal with it.
|
290
|
+
- **Complex Real Life**: Create a ServiceObject that knows everything it needs to know about how to build the rows. In some situations, a table row might need to represent multiple objects and the logic may be complex. Keeping the row building away from your Builder or Table classess keeps things simple.
|
291
|
+
|
292
|
+
#### Footer
|
293
|
+
Works in the same way as the header, except you use <code>footer_rows</code>. The only difference is that the footer does not repeat.
|
294
|
+
|
295
|
+
#### Table Options
|
296
|
+
A PrawnTable is very configurable. The goal of the Table component of **Thousand Island** is to make the configuration reusable throughout your application. There is a TableSettings class (see below) that you can subclass and use as a configuration object, but you can also override those settings for a specific table by setting a compatible Hash in your Table class like so:
|
297
|
+
```ruby
|
298
|
+
def settings
|
299
|
+
{
|
300
|
+
header_repeat: false
|
301
|
+
}
|
302
|
+
end
|
303
|
+
```
|
304
|
+
|
305
|
+
### Table Settings
|
306
|
+
You can use the defaults, or create your own <code>TableSettings</code> class as below:
|
307
|
+
```ruby
|
308
|
+
class MyTableSettings
|
309
|
+
def table_options
|
310
|
+
{...}
|
311
|
+
end
|
312
|
+
end
|
313
|
+
```
|
314
|
+
All the settings in the <code>table_options</code> Hash will be merged with the defaults and made available to any Table that uses your custom TableSettings class.
|
315
|
+
|
316
|
+
To get one of your Table subclasses to use your custom TableSettings subclass, do the following:
|
317
|
+
```ruby
|
318
|
+
class MyTable < ThousandIsland::Table
|
319
|
+
uses_settings MyTableSettings
|
320
|
+
|
321
|
+
...
|
322
|
+
|
323
|
+
end
|
324
|
+
```
|
325
|
+
|
326
|
+
### Using Tables in your Builder
|
327
|
+
Anywhere in your Builder, you can do:
|
328
|
+
```ruby
|
329
|
+
table = table_with MyTable
|
330
|
+
```
|
331
|
+
This initialises the Table class and gets it ready to build the body rows. You can then use it where appropriate to render the table in your PDF document:
|
332
|
+
```ruby
|
333
|
+
table.draw
|
334
|
+
|
335
|
+
# To override any of the settins either in the table or the TableSettings being used, just pass them as a Hash to the draw method:
|
336
|
+
table.draw(header_repeat: false)
|
337
|
+
```
|
338
|
+
|
258
339
|
## Default Styles
|
259
340
|
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
341
|
|
@@ -262,94 +343,117 @@ The default styles are:
|
|
262
343
|
##### body
|
263
344
|
```ruby
|
264
345
|
{
|
265
|
-
:
|
266
|
-
:
|
267
|
-
:
|
268
|
-
:
|
269
|
-
:
|
270
|
-
:
|
346
|
+
size: 10, # Inherited from default_style
|
347
|
+
style: :normal, # Inherited from default_style
|
348
|
+
align: :left, # Inherited from default_style
|
349
|
+
leading: 1, # Inherited from default_style
|
350
|
+
inline_format: true, # Inherited from default_style
|
351
|
+
color: "000000" # Inherited from default_style
|
271
352
|
}
|
272
353
|
```
|
273
354
|
##### h1
|
274
355
|
```ruby
|
275
356
|
{
|
276
|
-
:
|
277
|
-
:
|
278
|
-
:
|
279
|
-
:
|
280
|
-
:
|
281
|
-
:
|
357
|
+
size: 18, # Calcuated as 1.8 * default_style[:size]
|
358
|
+
style: :bold,
|
359
|
+
align: :left, # Inherited from default_style
|
360
|
+
leading: 8,
|
361
|
+
inline_format: true, # Inherited from default_style
|
362
|
+
color: "000000" # Inherited from default_style
|
282
363
|
}
|
283
364
|
```
|
284
365
|
##### h2
|
285
366
|
```ruby
|
286
367
|
{
|
287
|
-
:
|
288
|
-
:
|
289
|
-
:
|
290
|
-
:
|
291
|
-
:
|
292
|
-
:
|
368
|
+
size: 15, # Calcuated as 1.5 * default_style[:size]
|
369
|
+
style: :bold,
|
370
|
+
align: :left, # Inherited from default_style
|
371
|
+
leading: 4,
|
372
|
+
inline_format: true, # Inherited from default_style
|
373
|
+
color: "000000" # Inherited from default_style
|
293
374
|
}
|
294
375
|
```
|
295
376
|
##### h3
|
296
377
|
```ruby
|
297
378
|
{
|
298
|
-
:
|
299
|
-
:
|
300
|
-
:
|
301
|
-
:
|
302
|
-
:
|
303
|
-
:
|
379
|
+
size: 14, # Calcuated as 1.4 * default_style[:size]
|
380
|
+
style: :bold,
|
381
|
+
align: :left, # Inherited from default_style
|
382
|
+
leading: 4,
|
383
|
+
inline_format: true, # Inherited from default_style
|
384
|
+
color: "000000" # Inherited from default_style
|
304
385
|
}
|
305
386
|
```
|
306
387
|
##### h4
|
307
388
|
```ruby
|
308
389
|
{
|
309
|
-
:
|
310
|
-
:
|
311
|
-
:
|
312
|
-
:
|
313
|
-
:
|
314
|
-
:
|
390
|
+
size: 11, # Calcuated as 1.1 * default_style[:size]
|
391
|
+
style: :bold_italic,
|
392
|
+
align: :left, # Inherited from default_style
|
393
|
+
leading: 4,
|
394
|
+
inline_format: true, # Inherited from default_style
|
395
|
+
color: "000000" # Inherited from default_style
|
315
396
|
}
|
316
397
|
```
|
317
398
|
##### h5
|
318
399
|
```ruby
|
319
400
|
{
|
320
|
-
:
|
321
|
-
:
|
322
|
-
:
|
323
|
-
:
|
324
|
-
:
|
325
|
-
:
|
401
|
+
size: 10, # Calcuated as 1 * default_style[:size]
|
402
|
+
style: :normal, # Inherited from default_style
|
403
|
+
align: :left, # Inherited from default_style
|
404
|
+
leading: 4,
|
405
|
+
inline_format: true, # Inherited from default_style
|
406
|
+
color: "000000" # Inherited from default_style
|
326
407
|
}
|
327
408
|
```
|
328
409
|
##### h6
|
329
410
|
```ruby
|
330
411
|
{
|
331
|
-
:
|
332
|
-
:
|
333
|
-
:
|
334
|
-
:
|
335
|
-
:
|
336
|
-
:
|
412
|
+
size: 8.5, # Calcuated as 0.85 * default_style[:size]
|
413
|
+
style: :italic,
|
414
|
+
align: :left, # Inherited from default_style
|
415
|
+
leading: 4,
|
416
|
+
inline_format: true, # Inherited from default_style
|
417
|
+
color: "000000" # Inherited from default_style
|
337
418
|
}
|
338
419
|
```
|
339
420
|
##### footer
|
340
421
|
```ruby
|
341
422
|
{
|
342
|
-
:
|
343
|
-
:
|
344
|
-
:
|
345
|
-
:
|
346
|
-
:
|
347
|
-
:
|
423
|
+
size: 0.8, # Calcuated as 0.8 * default_style[:size]
|
424
|
+
style: :normal,
|
425
|
+
align: :left, # Inherited from default_style
|
426
|
+
leading: 1, # Inherited from default_style
|
427
|
+
inline_format: true, # Inherited from default_style
|
428
|
+
color: "666666"
|
348
429
|
}
|
349
430
|
```
|
431
|
+
## Default Table Settings
|
432
|
+
Override any of these settings (or the nested settings) using the following techniques (in order of precedence):
|
350
433
|
|
434
|
+
- Builder: <code>table.draw(_your_hash_)</code>
|
435
|
+
- Table class: <code>settings</code> method that returns a hash
|
436
|
+
- TableSettings class: <code>table_settings</code> method that returns a hash
|
437
|
+
|
438
|
+
### The full list of defaults
|
439
|
+
```ruby
|
440
|
+
{
|
441
|
+
position: :center,
|
442
|
+
width: pdf.bounds.width, # Equates to full page width
|
443
|
+
cell_style: {
|
444
|
+
borders: [:top, :bottom],
|
445
|
+
border_width: 0.5,
|
446
|
+
inline_format: true,
|
447
|
+
size: 10
|
448
|
+
},
|
449
|
+
header_repeat: true,
|
450
|
+
header_format: {
|
451
|
+
align: :center,
|
452
|
+
font_style: :bold
|
453
|
+
}
|
454
|
+
}
|
455
|
+
```
|
351
456
|
## To come...
|
352
|
-
- Easy (and repeatable) Table formatting
|
353
457
|
- Easy list rendering and styling (including nested lists)
|
354
458
|
- More flexibility in the Footer layout
|
355
459
|
- (Possibly) Command line functions to create common subclass files
|
data/lib/thousand_island.rb
CHANGED
@@ -1,19 +1,22 @@
|
|
1
|
-
require
|
1
|
+
require 'thousand_island/version'
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'prawn'
|
4
|
+
require 'prawn/table'
|
4
5
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require 'thousand_island/style_sheet'
|
7
|
+
require 'thousand_island/template'
|
8
|
+
require 'thousand_island/builder'
|
9
|
+
require 'thousand_island/table'
|
10
|
+
require 'thousand_island/table_settings'
|
8
11
|
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
12
|
+
require 'thousand_island/components'
|
13
|
+
require 'thousand_island/components/base'
|
14
|
+
require 'thousand_island/components/header'
|
15
|
+
require 'thousand_island/components/footer'
|
16
|
+
require 'thousand_island/components/body'
|
14
17
|
|
15
|
-
require
|
16
|
-
require
|
18
|
+
require 'thousand_island/utilities/utilities'
|
19
|
+
require 'thousand_island/utilities/style_hash'
|
17
20
|
|
18
21
|
module ThousandIsland
|
19
22
|
Error = Class.new(StandardError)
|
@@ -36,9 +36,7 @@ module ThousandIsland
|
|
36
36
|
def col2
|
37
37
|
start = col1_width
|
38
38
|
pdf.bounding_box([start, box_height], width: col2_width, height: box_height) do
|
39
|
-
|
40
|
-
pdf.send(k, v) if pdf.respond_to?(k)
|
41
|
-
end if options[:style]
|
39
|
+
inject_style
|
42
40
|
yield if block_given?
|
43
41
|
end
|
44
42
|
end
|
@@ -62,6 +60,10 @@ module ThousandIsland
|
|
62
60
|
options[:repeated]
|
63
61
|
end
|
64
62
|
|
63
|
+
def inject_style
|
64
|
+
options[:style].each { |k,v| pdf.send(k, v) if pdf.respond_to?(k) } if options[:style]
|
65
|
+
end
|
66
|
+
|
65
67
|
def self.defaults
|
66
68
|
{
|
67
69
|
height: 33,
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module ThousandIsland
|
2
|
+
# The Table class can be used to set the definition of your table, such as
|
3
|
+
# format and headings. You then inject the data from your Builder so that
|
4
|
+
# it can be rendered.
|
5
|
+
# You can declare a TableSettings class that you wish to use, otherwise
|
6
|
+
# the default will be used. To set a Table Setting class, add the following
|
7
|
+
# in your class body:
|
8
|
+
#
|
9
|
+
# uses_style MyTableSettings
|
10
|
+
#
|
11
|
+
class Table
|
12
|
+
|
13
|
+
attr_reader :pdf
|
14
|
+
attr_accessor :table_options
|
15
|
+
|
16
|
+
class << self
|
17
|
+
attr_writer :table_settings_klass
|
18
|
+
|
19
|
+
def table_settings_klass
|
20
|
+
@table_settings_klass ||= TableSettings
|
21
|
+
end
|
22
|
+
|
23
|
+
def uses_settings(klass)
|
24
|
+
self.table_settings_klass = klass
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(pdf)
|
29
|
+
@pdf = pdf
|
30
|
+
@table_options = {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def settings
|
34
|
+
{}
|
35
|
+
end
|
36
|
+
|
37
|
+
def draw(options={})
|
38
|
+
|
39
|
+
@table_options = merged_options(options)
|
40
|
+
|
41
|
+
table_options[:header] = prawn_header_setting
|
42
|
+
|
43
|
+
pdf.table(table_data, options_for_prawn) do |t|
|
44
|
+
t.row(0..num_header_rows - 1).font_style = table_options[:header_format][:font_style] unless header_rows.empty?
|
45
|
+
t.row(0..num_header_rows - 1).align = table_options[:header_format][:align] unless header_rows.empty?
|
46
|
+
t.row(-1..(0 - num_footer_rows)).font_style = :bold unless footer_rows.empty?
|
47
|
+
yield(t) if block_given?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def body_rows=(row_array)
|
52
|
+
raise ArgumentError.new('table_rows must be an array') unless row_array.is_a?(Array)
|
53
|
+
@body_rows = row_array
|
54
|
+
end
|
55
|
+
|
56
|
+
def body_rows
|
57
|
+
@body_rows ||= []
|
58
|
+
end
|
59
|
+
|
60
|
+
def header_rows=(row_array)
|
61
|
+
raise ArgumentError.new('header_cells must be an array') unless row_array.is_a?(Array)
|
62
|
+
@header_rows = row_array
|
63
|
+
end
|
64
|
+
|
65
|
+
def header_rows
|
66
|
+
@header_rows ||= []
|
67
|
+
end
|
68
|
+
|
69
|
+
def footer_rows=(row_array)
|
70
|
+
raise ArgumentError.new('footer_rows must be an array') unless row_array.is_a?(Array)
|
71
|
+
@footer_rows = row_array
|
72
|
+
end
|
73
|
+
|
74
|
+
def footer_rows
|
75
|
+
@footer_rows ||= []
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def table_data
|
82
|
+
data = body_rows
|
83
|
+
header_rows.reverse_each{ |row| data.unshift(row) }
|
84
|
+
footer_rows.each{ |row| data << row }
|
85
|
+
data
|
86
|
+
end
|
87
|
+
|
88
|
+
def num_footer_rows
|
89
|
+
footer_rows.size
|
90
|
+
end
|
91
|
+
|
92
|
+
def num_header_rows
|
93
|
+
header_rows.size
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def prawn_header_setting
|
98
|
+
return false if header_rows.empty? || table_options[:header_repeat] == false
|
99
|
+
header_rows.size
|
100
|
+
end
|
101
|
+
|
102
|
+
def options_for_prawn
|
103
|
+
table_options.select{ |k| [:cell_style, :header, :column_widths, :position, :width, :row_colors, ].include?(k)}
|
104
|
+
end
|
105
|
+
|
106
|
+
def merged_options(options={})
|
107
|
+
deep_merger.merge_options(options, settings, table_settings.settings)
|
108
|
+
end
|
109
|
+
|
110
|
+
def table_settings
|
111
|
+
@table_settings||= self.class.table_settings_klass.new(pdf, settings)
|
112
|
+
end
|
113
|
+
|
114
|
+
def deep_merger
|
115
|
+
@deep_merger ||= Utilities::DeepMerge::TableOptions
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module ThousandIsland
|
2
|
+
# The TableSettings class is where you set up styling rules that can be used by your Table class. You may create a class that inherits from TableSettings, and then use it in any of your tables. You can sub-class your TableStyles so you may define a master style for your app, but then have derived styles for special situations.
|
3
|
+
#
|
4
|
+
class TableSettings
|
5
|
+
|
6
|
+
attr_reader :pdf, :overrides
|
7
|
+
|
8
|
+
def initialize(pdf, overrides={})
|
9
|
+
@pdf = pdf
|
10
|
+
@overrides = overrides
|
11
|
+
end
|
12
|
+
|
13
|
+
#@TODO override this one!!! Do the docs...
|
14
|
+
def table_settings
|
15
|
+
{}
|
16
|
+
end
|
17
|
+
|
18
|
+
def settings
|
19
|
+
default_options.merge(table_settings.merge(overrides))
|
20
|
+
end
|
21
|
+
|
22
|
+
def default_options
|
23
|
+
{
|
24
|
+
width: pdf.bounds.width,
|
25
|
+
cell_style: cell_styles,
|
26
|
+
position: :center,
|
27
|
+
header_format: header_format,
|
28
|
+
header_repeat: true,
|
29
|
+
footer_format: footer_format
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def cell_styles
|
34
|
+
{
|
35
|
+
borders: [:top, :bottom],
|
36
|
+
border_width: 0.5,
|
37
|
+
inline_format: true,
|
38
|
+
size: 10
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def header_format
|
43
|
+
{
|
44
|
+
align: :center,
|
45
|
+
font_style: :bold
|
46
|
+
}
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
def footer_format
|
51
|
+
{
|
52
|
+
font_style: :bold
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -181,13 +181,13 @@ module ThousandIsland
|
|
181
181
|
end
|
182
182
|
|
183
183
|
def header_space
|
184
|
-
return
|
185
|
-
|
184
|
+
return 0 unless pdf_options[:header][:render]
|
185
|
+
pdf_options[:header][:height] + pdf_options[:header][:bottom_padding]
|
186
186
|
end
|
187
187
|
|
188
188
|
def footer_space
|
189
|
-
return
|
190
|
-
|
189
|
+
return 0 unless pdf_options[:footer][:render]
|
190
|
+
pdf_options[:footer][:height] + pdf_options[:footer][:top_padding]
|
191
191
|
end
|
192
192
|
|
193
193
|
|
@@ -237,7 +237,7 @@ module ThousandIsland
|
|
237
237
|
|
238
238
|
|
239
239
|
def deep_merger
|
240
|
-
@deep_merger ||= Utilities::DeepMerge
|
240
|
+
@deep_merger ||= Utilities::DeepMerge::TemplateOptions
|
241
241
|
end
|
242
242
|
|
243
243
|
# Called by method missing when a style is supplied with text, ie: h1 'Header'
|
@@ -3,53 +3,85 @@ module ThousandIsland
|
|
3
3
|
|
4
4
|
module DeepMerge
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
# Hashes work in order of precedence, the first in the array
|
9
|
-
# overrides, the second, etc.
|
10
|
-
#
|
11
|
-
# @param hashes [*Hash] A number of hashes to merge, in the order of precedence
|
12
|
-
#
|
13
|
-
# @return [Hash] the merged values
|
14
|
-
def self.merge_options(*hashes)
|
15
|
-
hashes.reverse!
|
6
|
+
def merge_for_key_and_nested_keys(key, keys, *hashes)
|
7
|
+
temp = {}
|
16
8
|
merged = {}
|
17
|
-
footer = merge_footer(*hashes)
|
18
|
-
header = merge_header(*hashes)
|
19
|
-
body = merge_body(*hashes)
|
20
9
|
hashes.each do |h|
|
21
|
-
|
10
|
+
keys.each do |k|
|
11
|
+
temp[k] = {} unless temp.has_key? k
|
12
|
+
temp[k].merge!(h[key][k]) if h[key] && h[key][k]
|
13
|
+
end
|
14
|
+
merged.merge!(h[key]) if h[key]
|
22
15
|
end
|
23
|
-
merged
|
24
|
-
merged[:header] = header
|
25
|
-
merged[:body] = body
|
26
|
-
merged
|
16
|
+
merged.merge(temp)
|
27
17
|
end
|
28
18
|
|
29
|
-
|
30
|
-
|
31
|
-
merge_for_key_and_nested_keys(:footer, keys, *hashes)
|
32
|
-
end
|
19
|
+
module TemplateOptions
|
20
|
+
extend ::ThousandIsland::Utilities::DeepMerge
|
33
21
|
|
34
|
-
|
35
|
-
|
36
|
-
|
22
|
+
# Take a number of hashes used for Template Options and merge them
|
23
|
+
# into one, respecting the structure and nesting according to
|
24
|
+
# the pdf options hash. Hashes work in order of precedence, the
|
25
|
+
# first in the array overrides, the second, etc.
|
26
|
+
#
|
27
|
+
# @param hashes [*Hash] A number of hashes to merge, in the order of precedence
|
28
|
+
#
|
29
|
+
# @return [Hash] the merged values
|
30
|
+
def self.merge_options(*hashes)
|
31
|
+
hashes.reverse!
|
32
|
+
merged = {}
|
33
|
+
footer = merge_footer(*hashes)
|
34
|
+
header = merge_header(*hashes)
|
35
|
+
body = merge_body(*hashes)
|
36
|
+
hashes.each do |h|
|
37
|
+
merged.merge!(h)
|
38
|
+
end
|
39
|
+
merged[:footer] = footer
|
40
|
+
merged[:header] = header
|
41
|
+
merged[:body] = body
|
42
|
+
merged
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.merge_footer(*hashes)
|
46
|
+
keys = [:numbering_options, :style]
|
47
|
+
merge_for_key_and_nested_keys(:footer, keys, *hashes)
|
48
|
+
end
|
37
49
|
|
38
|
-
|
39
|
-
|
50
|
+
def self.merge_header(*hashes)
|
51
|
+
merge_for_key_and_nested_keys(:header, [], *hashes)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.merge_body(*hashes)
|
55
|
+
merge_for_key_and_nested_keys(:body, [], *hashes)
|
56
|
+
end
|
40
57
|
end
|
41
58
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
hashes
|
46
|
-
|
47
|
-
|
48
|
-
|
59
|
+
module TableOptions
|
60
|
+
extend ::ThousandIsland::Utilities::DeepMerge
|
61
|
+
|
62
|
+
#Take a number of hashes used for Table Options and merge them
|
63
|
+
# into one, respecting the structure and nesting according to
|
64
|
+
# the pdf options hash. Hashes work in order of precedence, the
|
65
|
+
# first in the array overrides, the second, etc.
|
66
|
+
#
|
67
|
+
# @param hashes [*Hash] A number of hashes to merge, in the order of precedence
|
68
|
+
#
|
69
|
+
# @return [Hash] the merged values
|
70
|
+
def self.merge_options(*hashes)
|
71
|
+
hashes.reverse!
|
72
|
+
merged = {}
|
73
|
+
footer_format = merge_for_key_and_nested_keys(:footer_format, [], *hashes)
|
74
|
+
header_format = merge_for_key_and_nested_keys(:header_format, [], *hashes)
|
75
|
+
cell_style = merge_for_key_and_nested_keys(:cell_style, [], *hashes)
|
76
|
+
hashes.each do |h|
|
77
|
+
merged.merge!(h)
|
49
78
|
end
|
50
|
-
merged
|
79
|
+
merged[:footer_format] = footer_format
|
80
|
+
merged[:header_format] = header_format
|
81
|
+
merged[:cell_style] = cell_style
|
82
|
+
merged
|
51
83
|
end
|
52
|
-
|
84
|
+
|
53
85
|
end
|
54
86
|
|
55
87
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -29,14 +29,10 @@ module ThousandIsland
|
|
29
29
|
|
30
30
|
before :each do
|
31
31
|
allow(builder).to receive(:template) { template }
|
32
|
-
# klass.send(:define_method, :header_content, ->{})
|
33
|
-
# klass.send(:define_method, :body_content, ->{})
|
34
|
-
# klass.send(:define_method, :footer_content, ->{})
|
35
32
|
end
|
36
33
|
context 'exists' do
|
37
34
|
|
38
35
|
it 'header_content' do
|
39
|
-
# allow(builder).to receive(:header_content)
|
40
36
|
expect(builder).to receive(:header_content)
|
41
37
|
builder.send(:draw_header)
|
42
38
|
end
|
@@ -101,6 +97,12 @@ module ThousandIsland
|
|
101
97
|
end
|
102
98
|
end
|
103
99
|
end
|
100
|
+
|
101
|
+
it 'table_with instantiates the class' do
|
102
|
+
dummy_table = double
|
103
|
+
expect(dummy_table).to receive(:new).with(subject.pdf)
|
104
|
+
subject.table_with dummy_table
|
105
|
+
end
|
104
106
|
end
|
105
107
|
end
|
106
108
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module ThousandIsland
|
2
|
+
describe Table do
|
3
|
+
let(:pdf) { Prawn::Document.new({:page_size => "A4", :page_layout => :portrait}) }
|
4
|
+
|
5
|
+
subject { described_class.new(pdf) }
|
6
|
+
|
7
|
+
context 'when TableStyle is not set' do
|
8
|
+
it 'sets default style' do
|
9
|
+
expect(described_class.table_settings_klass).to eq(TableSettings)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'when TableStyle is set' do
|
14
|
+
it 'is used' do
|
15
|
+
klass = described_class.dup
|
16
|
+
Dummy = Class.new
|
17
|
+
klass.uses_settings(Dummy)
|
18
|
+
expect(klass.table_settings_klass).to eq(Dummy)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#header_rows' do
|
23
|
+
it 'defaults to an empty array' do
|
24
|
+
expect(subject.header_rows).to eq([])
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'forces array' do
|
28
|
+
expect{ subject.header_rows = 'not an array' }.to raise_error(ArgumentError)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'can be set with an array' do
|
32
|
+
expect{ subject.header_rows = %w'it is an array' }.to_not raise_error
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#body_rows' do
|
37
|
+
it 'defaults to an empty array' do
|
38
|
+
expect(subject.body_rows).to eq([])
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'forces array' do
|
42
|
+
expect{ subject.body_rows = 'not an array' }.to raise_error(ArgumentError)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'can be set with an array' do
|
46
|
+
expect{ subject.body_rows = %w'it is an array' }.to_not raise_error
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#footer_rows' do
|
51
|
+
it 'defaults to an empty array' do
|
52
|
+
expect(subject.footer_rows).to eq([])
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'forces array' do
|
56
|
+
expect{ subject.footer_rows = 'not an array' }.to raise_error(ArgumentError)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'can be set with an array' do
|
60
|
+
expect{ subject.footer_rows = %w'it is an array' }.to_not raise_error
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'header' do
|
65
|
+
describe 'repeats' do
|
66
|
+
let(:body_rows) { [] }
|
67
|
+
let(:header_rows) { [[' ', { content: "Prefix", colspan: 2 } ], ['The Number', 'As', 'Bs'] ] }
|
68
|
+
|
69
|
+
before do
|
70
|
+
(1..50).each{ |n| body_rows.push( ["#{n}", "A#{n}", "B#{n}"] ) }
|
71
|
+
subject.body_rows = body_rows
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'all rows' do
|
75
|
+
subject.header_rows = header_rows
|
76
|
+
draw_the_table
|
77
|
+
output = PDF::Inspector::Page.analyze(subject.pdf.render)
|
78
|
+
expect(output.pages[0][:strings][0..4]).to eq(output.pages[1][:strings][0..4])
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'unless specified not to' do
|
82
|
+
subject.header_rows = header_rows
|
83
|
+
draw_the_table({header_repeat: false})
|
84
|
+
output = PDF::Inspector::Page.analyze(subject.pdf.render)
|
85
|
+
expect(output.pages[0][:strings][0..4]).to_not eq(output.pages[1][:strings][0..4])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def draw_the_table(opts={})
|
93
|
+
subject.pdf.bounding_box( [0, std_doc_height], height: std_doc_height, width: std_doc_width ) do
|
94
|
+
subject.draw(opts)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def std_doc_height
|
99
|
+
840
|
100
|
+
end
|
101
|
+
|
102
|
+
def std_doc_width
|
103
|
+
595
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -8,7 +8,7 @@ module ThousandIsland
|
|
8
8
|
options = { op_one: 1, op_two: 2 }
|
9
9
|
defaults = subject.send(:defaults)
|
10
10
|
component_defaults = subject.send(:component_defaults)
|
11
|
-
deep_merger = ThousandIsland::Utilities::DeepMerge
|
11
|
+
deep_merger = ThousandIsland::Utilities::DeepMerge::TemplateOptions
|
12
12
|
expect(deep_merger).to receive(:merge_options).with(options, [], defaults, component_defaults)
|
13
13
|
subject.send(:setup_document_options, options)
|
14
14
|
end
|
@@ -16,7 +16,6 @@ module ThousandIsland
|
|
16
16
|
it 'method missing' do
|
17
17
|
expect{ subject.made_up_method }.to raise_error(NoMethodError)
|
18
18
|
end
|
19
|
-
|
20
19
|
end
|
21
20
|
|
22
21
|
context 'Style Sheet' do
|
@@ -1,60 +1,44 @@
|
|
1
1
|
module ThousandIsland
|
2
2
|
module Utilities
|
3
|
+
module DeepMerge
|
3
4
|
|
4
|
-
|
5
|
+
describe TemplateOptions do
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
footer: {
|
12
|
-
height: 33,
|
13
|
-
repeated: true,
|
14
|
-
numbering_options: {
|
15
|
-
align: :right,
|
16
|
-
start_count_at: 1,
|
17
|
-
},
|
18
|
-
number_pages: true,
|
19
|
-
numbering_string: '<page>',
|
20
|
-
style: {
|
21
|
-
font_size: 23
|
7
|
+
|
8
|
+
let(:default) {{
|
9
|
+
header:{
|
10
|
+
height: 33,
|
11
|
+
repeated: true,
|
22
12
|
},
|
23
|
-
|
24
|
-
}}
|
25
|
-
let(:options) {{
|
26
|
-
header: {
|
13
|
+
footer: {
|
27
14
|
height: 33,
|
28
|
-
repeated:
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
15
|
+
repeated: true,
|
16
|
+
numbering_options: {
|
17
|
+
align: :right,
|
18
|
+
start_count_at: 1,
|
19
|
+
},
|
20
|
+
number_pages: true,
|
21
|
+
numbering_string: '<page>',
|
22
|
+
style: {
|
23
|
+
font_size: 23
|
24
|
+
},
|
36
25
|
},
|
37
|
-
}
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
repeated: true,
|
43
|
-
},
|
44
|
-
footer: {
|
45
|
-
height: 50,
|
46
|
-
repeated: false,
|
47
|
-
numbering_options: {
|
48
|
-
align: :left,
|
26
|
+
}}
|
27
|
+
let(:options) {{
|
28
|
+
header: {
|
29
|
+
height: 33,
|
30
|
+
repeated: false,
|
49
31
|
},
|
50
|
-
|
51
|
-
|
32
|
+
footer: {
|
33
|
+
height: 40,
|
34
|
+
repeated: true,
|
35
|
+
numbering_options: {
|
36
|
+
align: :right,
|
37
|
+
start_count_at: 2,
|
38
|
+
},
|
52
39
|
},
|
53
|
-
}
|
54
|
-
|
55
|
-
|
56
|
-
it 'deep merges the hashes intelligently' do
|
57
|
-
expected = {
|
40
|
+
}}
|
41
|
+
let(:over) {{
|
58
42
|
header: {
|
59
43
|
height: 50,
|
60
44
|
repeated: true,
|
@@ -64,18 +48,96 @@ module ThousandIsland
|
|
64
48
|
repeated: false,
|
65
49
|
numbering_options: {
|
66
50
|
align: :left,
|
67
|
-
start_count_at: 2,
|
68
51
|
},
|
69
|
-
number_pages: true,
|
70
|
-
numbering_string: '<page>',
|
71
52
|
style: {
|
72
53
|
font_size: 5
|
73
54
|
},
|
74
55
|
},
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
56
|
+
}}
|
57
|
+
|
58
|
+
it 'deep merges the hashes intelligently' do
|
59
|
+
expected = {
|
60
|
+
header: {
|
61
|
+
height: 50,
|
62
|
+
repeated: true,
|
63
|
+
},
|
64
|
+
footer: {
|
65
|
+
height: 50,
|
66
|
+
repeated: false,
|
67
|
+
numbering_options: {
|
68
|
+
align: :left,
|
69
|
+
start_count_at: 2,
|
70
|
+
},
|
71
|
+
number_pages: true,
|
72
|
+
numbering_string: '<page>',
|
73
|
+
style: {
|
74
|
+
font_size: 5
|
75
|
+
},
|
76
|
+
},
|
77
|
+
body: {},
|
78
|
+
}
|
79
|
+
final = described_class.merge_options(over, options, default)
|
80
|
+
expect(final).to eq(expected)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe TableOptions do
|
85
|
+
|
86
|
+
let(:default) {{
|
87
|
+
header_repeat: true,
|
88
|
+
width: 600,
|
89
|
+
cell_style: {
|
90
|
+
borders: [:top, :bottom],
|
91
|
+
border_width: 0.5,
|
92
|
+
inline_format: true,
|
93
|
+
size: 10
|
94
|
+
},
|
95
|
+
position: :center,
|
96
|
+
header_format: {
|
97
|
+
align: :center,
|
98
|
+
font_style: :bold
|
99
|
+
},
|
100
|
+
footer_format: {
|
101
|
+
font_style: :bold
|
102
|
+
}
|
103
|
+
}}
|
104
|
+
let(:options) {{
|
105
|
+
header_format: {
|
106
|
+
align: :left,
|
107
|
+
},
|
108
|
+
header_repeat: false
|
109
|
+
}}
|
110
|
+
let(:over) {{
|
111
|
+
header_format: {
|
112
|
+
align: :right,
|
113
|
+
},
|
114
|
+
cell_style: {
|
115
|
+
size: 12
|
116
|
+
},
|
117
|
+
}}
|
118
|
+
|
119
|
+
it 'deep merges the hashes intelligently' do
|
120
|
+
expected = {
|
121
|
+
header_repeat: false,
|
122
|
+
width: 600,
|
123
|
+
cell_style: {
|
124
|
+
borders: [:top, :bottom],
|
125
|
+
border_width: 0.5,
|
126
|
+
inline_format: true,
|
127
|
+
size: 12
|
128
|
+
},
|
129
|
+
position: :center,
|
130
|
+
header_format: {
|
131
|
+
align: :right,
|
132
|
+
font_style: :bold
|
133
|
+
},
|
134
|
+
footer_format: {
|
135
|
+
font_style: :bold
|
136
|
+
}
|
137
|
+
}
|
138
|
+
final = described_class.merge_options(over, options, default)
|
139
|
+
expect(final).to eq(expected)
|
140
|
+
end
|
79
141
|
end
|
80
142
|
end
|
81
143
|
end
|
data/thousand_island.gemspec
CHANGED
@@ -4,27 +4,30 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'thousand_island/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'thousand_island'
|
8
8
|
spec.version = ThousandIsland::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
9
|
+
spec.authors = ['Colin Weight']
|
10
|
+
spec.email = ['colin@colinweight.com.au']
|
11
11
|
spec.description = %q{Dressing for Prawn}
|
12
12
|
spec.summary = %q{A library that helps with common layout elements in PDFs.}
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
13
|
+
spec.homepage = 'https://github.com/colinweight/thousand_island'
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
19
|
+
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.
|
21
|
+
spec.required_ruby_version = '>= 1.9.3'
|
22
|
+
spec.add_dependency 'prawn', '~> 1.3.0'
|
23
|
+
spec.add_dependency 'prawn-table', '~> 0.2.1'
|
22
24
|
|
23
|
-
spec.add_development_dependency
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
29
|
-
spec.add_development_dependency
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
26
|
+
spec.add_development_dependency 'rake'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
28
|
+
spec.add_development_dependency 'guard', '~> 2.6.1'
|
29
|
+
spec.add_development_dependency 'guard-rspec', '~> 4.3.1'
|
30
|
+
spec.add_development_dependency 'pdf-inspector', '~> 1.2.0'
|
31
|
+
spec.add_development_dependency 'yard', '~> 0.8.7'
|
32
|
+
spec.add_development_dependency 'codeclimate-test-reporter'
|
30
33
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thousand_island
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Colin Weight
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prawn
|
@@ -16,14 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: 1.3.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: 1.3.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: prawn-table
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.2.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.2.1
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +108,20 @@ dependencies:
|
|
94
108
|
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: 4.3.1
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pdf-inspector
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.2.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.2.0
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
126
|
name: yard
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,6 +173,8 @@ files:
|
|
145
173
|
- lib/thousand_island/components/footer.rb
|
146
174
|
- lib/thousand_island/components/header.rb
|
147
175
|
- lib/thousand_island/style_sheet.rb
|
176
|
+
- lib/thousand_island/table.rb
|
177
|
+
- lib/thousand_island/table_settings.rb
|
148
178
|
- lib/thousand_island/template.rb
|
149
179
|
- lib/thousand_island/utilities/style_hash.rb
|
150
180
|
- lib/thousand_island/utilities/utilities.rb
|
@@ -156,6 +186,7 @@ files:
|
|
156
186
|
- spec/thousand_island/components/footer_spec.rb
|
157
187
|
- spec/thousand_island/components/header_spec.rb
|
158
188
|
- spec/thousand_island/style_sheet_spec.rb
|
189
|
+
- spec/thousand_island/table_spec.rb
|
159
190
|
- spec/thousand_island/template_spec.rb
|
160
191
|
- spec/thousand_island/utilities/style_hash_spec.rb
|
161
192
|
- spec/thousand_island/utilities/utilities_spec.rb
|
@@ -173,7 +204,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
173
204
|
requirements:
|
174
205
|
- - ">="
|
175
206
|
- !ruby/object:Gem::Version
|
176
|
-
version:
|
207
|
+
version: 1.9.3
|
177
208
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
209
|
requirements:
|
179
210
|
- - ">="
|
@@ -193,6 +224,7 @@ test_files:
|
|
193
224
|
- spec/thousand_island/components/footer_spec.rb
|
194
225
|
- spec/thousand_island/components/header_spec.rb
|
195
226
|
- spec/thousand_island/style_sheet_spec.rb
|
227
|
+
- spec/thousand_island/table_spec.rb
|
196
228
|
- spec/thousand_island/template_spec.rb
|
197
229
|
- spec/thousand_island/utilities/style_hash_spec.rb
|
198
230
|
- spec/thousand_island/utilities/utilities_spec.rb
|