squib 0.0.4 → 0.0.5
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +9 -0
- data/README.md +38 -33
- data/Rakefile +1 -1
- data/bin/squib +6 -6
- data/lib/squib.rb +8 -8
- data/lib/squib/api/background.rb +3 -3
- data/lib/squib/api/data.rb +5 -6
- data/lib/squib/api/image.rb +13 -10
- data/lib/squib/api/save.rb +4 -5
- data/lib/squib/api/settings.rb +4 -4
- data/lib/squib/api/shapes.rb +20 -20
- data/lib/squib/api/text.rb +11 -11
- data/lib/squib/api/units.rb +4 -4
- data/lib/squib/card.rb +5 -5
- data/lib/squib/commands/new.rb +5 -5
- data/lib/squib/constants.rb +10 -10
- data/lib/squib/deck.rb +24 -22
- data/lib/squib/graphics/background.rb +3 -3
- data/lib/squib/graphics/image.rb +13 -6
- data/lib/squib/graphics/save_doc.rb +13 -11
- data/lib/squib/graphics/save_images.rb +3 -3
- data/lib/squib/graphics/shapes.rb +9 -8
- data/lib/squib/graphics/text.rb +61 -59
- data/lib/squib/input_helpers.rb +13 -13
- data/lib/squib/progress.rb +4 -4
- data/lib/squib/project_template/Gemfile +1 -1
- data/lib/squib/project_template/deck.rb +3 -3
- data/lib/squib/version.rb +6 -2
- data/samples/autoscale_font.rb +4 -4
- data/samples/basic.rb +6 -7
- data/samples/cairo_access.rb +27 -0
- data/samples/colors.rb +2 -2
- data/samples/custom-layout.yml +5 -5
- data/samples/custom_config.rb +4 -4
- data/samples/draw_shapes.rb +8 -8
- data/samples/hello_world.rb +2 -3
- data/samples/load_images.rb +6 -1
- data/samples/portrait-landscape.rb +7 -7
- data/samples/ranges.rb +13 -14
- data/samples/save_pdf.rb +2 -2
- data/samples/text_options.rb +17 -17
- data/samples/tgc_proofs.rb +3 -3
- data/samples/use_layout.rb +3 -3
- data/spec/api/api_text_spec.rb +11 -17
- data/spec/commands/new_spec.rb +10 -10
- data/spec/data/easy-circular-extends.yml +1 -1
- data/spec/data/hard-circular-extends.yml +2 -2
- data/spec/data/multi-extends-single-entry.yml +3 -3
- data/spec/data/multi-level-extends.yml +1 -1
- data/spec/data/no-extends.yml +2 -2
- data/spec/data/pre-extends.yml +1 -1
- data/spec/data/self-circular-extends.yml +1 -1
- data/spec/data/single-extends.yml +1 -1
- data/spec/data/single-level-multi-extends.yml +1 -1
- data/spec/deck_spec.rb +62 -62
- data/spec/graphics/graphics_images_spec.rb +79 -0
- data/spec/graphics/graphics_save_doc_spec.rb +66 -0
- data/spec/graphics/graphics_shapes_spec.rb +74 -0
- data/spec/graphics/graphics_text_spec.rb +135 -0
- data/spec/input_helpers_spec.rb +61 -40
- data/spec/samples_run_spec.rb +6 -6
- data/spec/spec_helper.rb +32 -1
- data/squib.gemspec +21 -21
- metadata +22 -14
@@ -9,19 +9,20 @@ module Squib
|
|
9
9
|
# @option opts file [String] the name of the PDF file to save. See {file:README.md#Specifying_Files Specifying Files}
|
10
10
|
# @option opts dir [String] (_output) the directory to save to. Created if it doesn't exist.
|
11
11
|
# @option opts margin [Integer] (75) the margin around the outside of the page
|
12
|
-
# @option opts gap [Integer] (0) the space in pixels between the cards
|
12
|
+
# @option opts gap [Integer] (0) the space in pixels between the cards
|
13
13
|
# @option opts trim [Integer] (0) the space around the edge of each card to trim (e.g. to cut off the bleed margin for print-and-play)
|
14
14
|
# @return [nil]
|
15
15
|
# @api public
|
16
16
|
def save_pdf(opts = {})
|
17
|
-
p = needs(opts, [:file_to_save, :creatable_dir, :margin, :gap, :trim])
|
18
|
-
width
|
17
|
+
p = needs(opts, [:range, :file_to_save, :creatable_dir, :margin, :gap, :trim])
|
18
|
+
width = 11 * @dpi
|
19
|
+
height = 8.5 * @dpi #TODO: allow this to be specified too
|
19
20
|
cc = Cairo::Context.new(Cairo::PDFSurface.new("#{p[:dir]}/#{p[:file]}", width, height))
|
20
|
-
x = p[:margin]
|
21
|
-
|
21
|
+
x = p[:margin]
|
22
|
+
y = p[:margin]
|
22
23
|
@progress_bar.start("Saving PDF to #{p[:dir]}/#{p[:file]}", p[:range].size) do |bar|
|
23
|
-
|
24
|
-
surface = trim(
|
24
|
+
p[:range].each do |i|
|
25
|
+
surface = trim(@cards[i].cairo_surface, p[:trim], @width, @height)
|
25
26
|
cc.set_source(surface, x, y)
|
26
27
|
cc.paint
|
27
28
|
bar.increment
|
@@ -30,16 +31,17 @@ module Squib
|
|
30
31
|
x = p[:margin]
|
31
32
|
y += surface.height + p[:gap]
|
32
33
|
if y > (height - surface.height - p[:margin])
|
33
|
-
x = p[:margin]
|
34
|
+
x = p[:margin]
|
35
|
+
y = p[:margin]
|
34
36
|
cc.show_page #next page
|
35
37
|
end
|
36
38
|
end
|
37
39
|
end
|
38
|
-
|
40
|
+
end
|
39
41
|
end
|
40
42
|
|
41
43
|
# :nodoc:
|
42
|
-
# @api private
|
44
|
+
# @api private
|
43
45
|
def trim(surface, trim, width, height)
|
44
46
|
if trim > 0
|
45
47
|
tmp = Cairo::ImageSurface.new(width-2*trim, height-2*trim)
|
@@ -52,4 +54,4 @@ module Squib
|
|
52
54
|
end
|
53
55
|
|
54
56
|
end
|
55
|
-
end
|
57
|
+
end
|
@@ -2,7 +2,7 @@ module Squib
|
|
2
2
|
class Card
|
3
3
|
|
4
4
|
# :nodoc:
|
5
|
-
# @api private
|
5
|
+
# @api private
|
6
6
|
def save_png(i, dir, prefix, do_rotate, angle)
|
7
7
|
if [true, :clockwise, :counterclockwise].include?(do_rotate)
|
8
8
|
surface = rotated_image(angle)
|
@@ -24,10 +24,10 @@ module Squib
|
|
24
24
|
rotated_cc.target
|
25
25
|
end
|
26
26
|
# :nodoc:
|
27
|
-
# @api private
|
27
|
+
# @api private
|
28
28
|
def write_png(surface, i, dir, prefix)
|
29
29
|
surface.write_to_png("#{dir}/#{prefix}#{i}.png")
|
30
30
|
end
|
31
31
|
|
32
32
|
end
|
33
|
-
end
|
33
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
module Squib
|
2
2
|
class Card
|
3
|
-
|
3
|
+
|
4
4
|
# :nodoc:
|
5
|
-
# @api private
|
5
|
+
# @api private
|
6
6
|
def rect(x, y, width, height, x_radius, y_radius, fill_color, stroke_color, stroke_width)
|
7
|
-
width
|
7
|
+
width = @width if width == :native
|
8
|
+
height = @height if height == :native
|
8
9
|
use_cairo do |cc|
|
9
10
|
cc.rounded_rectangle(x, y, width, height, x_radius, y_radius)
|
10
11
|
cc.set_source_color(stroke_color)
|
@@ -17,7 +18,7 @@ module Squib
|
|
17
18
|
end
|
18
19
|
|
19
20
|
# :nodoc:
|
20
|
-
# @api private
|
21
|
+
# @api private
|
21
22
|
def circle(x, y, radius, fill_color, stroke_color, stroke_width)
|
22
23
|
use_cairo do |cc|
|
23
24
|
cc.circle(x, y, radius)
|
@@ -31,7 +32,7 @@ module Squib
|
|
31
32
|
end
|
32
33
|
|
33
34
|
# :nodoc:
|
34
|
-
# @api private
|
35
|
+
# @api private
|
35
36
|
def triangle(x1, y1, x2, y2, x3, y3, fill_color, stroke_color, stroke_width)
|
36
37
|
use_cairo do |cc|
|
37
38
|
cc.triangle(x1, y1, x2, y2, x3, y3)
|
@@ -45,7 +46,7 @@ module Squib
|
|
45
46
|
end
|
46
47
|
|
47
48
|
# :nodoc:
|
48
|
-
# @api private
|
49
|
+
# @api private
|
49
50
|
def line(x1, y1, x2, y2, stroke_color, stroke_width)
|
50
51
|
use_cairo do |cc|
|
51
52
|
cc.move_to(x1, y1)
|
@@ -55,6 +56,6 @@ module Squib
|
|
55
56
|
cc.stroke
|
56
57
|
end
|
57
58
|
end
|
58
|
-
|
59
|
+
|
59
60
|
end
|
60
|
-
end
|
61
|
+
end
|
data/lib/squib/graphics/text.rb
CHANGED
@@ -4,114 +4,116 @@ module Squib
|
|
4
4
|
class Card
|
5
5
|
|
6
6
|
# :nodoc:
|
7
|
-
# @api private
|
8
|
-
def draw_text_hint(x,y,layout, color)
|
7
|
+
# @api private
|
8
|
+
def draw_text_hint(cc,x,y,layout, color,angle)
|
9
9
|
color = @deck.text_hint if color.to_s.eql? 'off' and not @deck.text_hint.to_s.eql? 'off'
|
10
|
-
return if color.to_s.eql? 'off'
|
10
|
+
return if color.to_s.eql? 'off' or color.nil?
|
11
11
|
# when w,h < 0, it was never set. extents[1] are ink extents
|
12
12
|
w = layout.width / Pango::SCALE
|
13
13
|
w = layout.extents[1].width / Pango::SCALE if w < 0
|
14
14
|
h = layout.height / Pango::SCALE
|
15
15
|
h = layout.extents[1].height / Pango::SCALE if h < 0
|
16
|
-
|
16
|
+
cc.rounded_rectangle(x,y,w,h,0,0)
|
17
|
+
cc.set_source_color(color)
|
18
|
+
cc.set_line_width(2.0)
|
19
|
+
cc.stroke
|
17
20
|
end
|
18
21
|
|
19
22
|
# :nodoc:
|
20
|
-
# @api private
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
layout.ellipsize =
|
23
|
+
# @api private
|
24
|
+
def set_ellipsize!(layout, ellipsize)
|
25
|
+
case ellipsize.to_s.downcase
|
26
|
+
when 'none', 'false'
|
27
|
+
layout.ellipsize = Pango::Layout::ELLIPSIZE_NONE
|
28
|
+
when 'start'
|
29
|
+
layout.ellipsize = Pango::Layout::ELLIPSIZE_START
|
30
|
+
when 'middle'
|
31
|
+
layout.ellipsize = Pango::Layout::ELLIPSIZE_MIDDLE
|
32
|
+
when 'end', 'true'
|
33
|
+
layout.ellipsize = Pango::Layout::ELLIPSIZE_END
|
31
34
|
end
|
32
|
-
layout
|
33
35
|
end
|
34
36
|
|
35
37
|
# :nodoc:
|
36
|
-
# @api private
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
}
|
46
|
-
layout.wrap = h[wrap]
|
38
|
+
# @api private
|
39
|
+
def set_wrap!(layout, wrap)
|
40
|
+
case wrap.to_s.downcase
|
41
|
+
when 'word'
|
42
|
+
layout.wrap = Pango::Layout::WRAP_WORD
|
43
|
+
when 'char'
|
44
|
+
layout.wrap = Pango::Layout::WRAP_CHAR
|
45
|
+
when 'word_char', 'true'
|
46
|
+
layout.wrap = Pango::Layout::WRAP_WORD_CHAR
|
47
47
|
end
|
48
|
-
layout
|
49
48
|
end
|
50
49
|
|
51
50
|
# :nodoc:
|
52
|
-
# @api private
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
51
|
+
# @api private
|
52
|
+
def set_align!(layout, align)
|
53
|
+
case align.to_s.downcase
|
54
|
+
when 'left'
|
55
|
+
layout.alignment = Pango::ALIGN_LEFT
|
56
|
+
when 'right'
|
57
|
+
layout.alignment = Pango::ALIGN_RIGHT
|
58
|
+
when 'center'
|
59
|
+
layout.alignment = Pango::ALIGN_CENTER
|
60
60
|
end
|
61
|
-
layout
|
62
61
|
end
|
63
62
|
|
64
63
|
# :nodoc:
|
65
|
-
# @api private
|
66
|
-
def valign(cc, layout, x, y, valign)
|
67
|
-
if layout.height > 0
|
64
|
+
# @api private
|
65
|
+
def valign!(cc, layout, x, y, valign)
|
66
|
+
if layout.height > 0
|
68
67
|
ink_extents = layout.extents[1]
|
69
|
-
case valign
|
70
|
-
when
|
68
|
+
case valign.to_s
|
69
|
+
when 'middle'
|
71
70
|
cc.move_to(x, y + (layout.height - ink_extents.height) / (2 * Pango::SCALE))
|
72
|
-
when
|
71
|
+
when 'bottom'
|
73
72
|
cc.move_to(x, y + (layout.height - ink_extents.height) / Pango::SCALE)
|
74
73
|
end
|
75
74
|
end
|
76
75
|
end
|
77
76
|
|
78
77
|
# :nodoc:
|
79
|
-
# @api private
|
80
|
-
def
|
78
|
+
# @api private
|
79
|
+
def set_wh!(layout, width, height)
|
81
80
|
layout.width = width * Pango::SCALE unless width.nil? || width == :native
|
82
81
|
layout.height = height * Pango::SCALE unless height.nil? || height == :native
|
83
82
|
layout
|
84
83
|
end
|
85
84
|
|
86
85
|
# :nodoc:
|
87
|
-
# @api private
|
88
|
-
def text(str, font, font_size, color,
|
86
|
+
# @api private
|
87
|
+
def text(str, font, font_size, color,
|
89
88
|
x, y, width, height,
|
90
|
-
markup, justify, wrap, ellipsize,
|
89
|
+
markup, justify, wrap, ellipsize,
|
91
90
|
spacing, align, valign, hint, angle)
|
92
|
-
Squib.logger.debug {"Placing '#{str}'' with font '#{font}' @ #{x}, #{y}, color: #{color},
|
91
|
+
Squib.logger.debug {"Placing '#{str}'' with font '#{font}' @ #{x}, #{y}, color: #{color}, angle: #{angle} etc."}
|
93
92
|
use_cairo do |cc|
|
94
93
|
cc.set_source_color(color)
|
95
|
-
cc.
|
94
|
+
cc.translate(x,y)
|
96
95
|
cc.rotate(angle)
|
96
|
+
cc.translate(-1*x,-1*y)
|
97
|
+
cc.move_to(x,y)
|
98
|
+
|
97
99
|
layout = cc.create_pango_layout
|
98
100
|
font_desc = Pango::FontDescription.new(font)
|
99
101
|
font_desc.size = font_size * Pango::SCALE unless font_size.nil?
|
100
102
|
layout.font_description = font_desc
|
101
103
|
layout.text = str.to_s
|
102
104
|
layout.markup = str.to_s if markup
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
105
|
+
set_wh!(layout, width, height)
|
106
|
+
set_wrap!(layout, wrap)
|
107
|
+
set_ellipsize!(layout, ellipsize)
|
108
|
+
set_align!(layout, align)
|
107
109
|
layout.justify = justify unless justify.nil?
|
108
|
-
layout.spacing = spacing * Pango::SCALE unless spacing.nil?
|
109
|
-
cc.update_pango_layout(layout)
|
110
|
-
valign(cc, layout, x,y, valign)
|
110
|
+
layout.spacing = spacing * Pango::SCALE unless spacing.nil?
|
111
|
+
cc.update_pango_layout(layout)
|
112
|
+
valign!(cc, layout, x, y, valign)
|
111
113
|
cc.update_pango_layout(layout) ; cc.show_pango_layout(layout)
|
112
|
-
draw_text_hint(x,y,layout,hint)
|
114
|
+
draw_text_hint(cc,x,y,layout,hint,angle)
|
113
115
|
end
|
114
116
|
end
|
115
117
|
|
116
118
|
end
|
117
|
-
end
|
119
|
+
end
|
data/lib/squib/input_helpers.rb
CHANGED
@@ -8,11 +8,11 @@ module Squib
|
|
8
8
|
# :nodoc:
|
9
9
|
# @api private
|
10
10
|
def needs(opts, params)
|
11
|
-
Squib.logger.debug {"
|
11
|
+
Squib.logger.debug {"Method #{caller(1,1)} was given the following opts: #{opts}"}
|
12
12
|
opts = layoutify(opts) if params.include? :layout
|
13
13
|
opts = Squib::SYSTEM_DEFAULTS.merge(opts)
|
14
14
|
opts = expand_singletons(opts, params)
|
15
|
-
opts = rangeify(opts) if params.include? :range
|
15
|
+
opts = rangeify(opts) if params.include? :range
|
16
16
|
opts = fileify(opts) if params.include? :file
|
17
17
|
opts = fileify(opts, false) if params.include? :file_to_save
|
18
18
|
opts = colorify(opts, true) if params.include? :nillable_color
|
@@ -37,7 +37,7 @@ module Squib
|
|
37
37
|
Squib::EXPANDING_PARAMS.each_pair do |param_name, api_param|
|
38
38
|
if needed_params.include? param_name
|
39
39
|
unless opts[api_param].respond_to?(:each)
|
40
|
-
opts[api_param] = [opts[api_param]] * @cards.size
|
40
|
+
opts[api_param] = [opts[api_param]] * @cards.size
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -50,8 +50,8 @@ module Squib
|
|
50
50
|
# :nodoc:
|
51
51
|
# @api private
|
52
52
|
def layoutify(opts)
|
53
|
-
unless opts[:layout].respond_to?(:each)
|
54
|
-
opts[:layout] = [opts[:layout]] * @cards.size
|
53
|
+
unless opts[:layout].respond_to?(:each)
|
54
|
+
opts[:layout] = [opts[:layout]] * @cards.size
|
55
55
|
end
|
56
56
|
opts[:layout].each_with_index do |layout, i|
|
57
57
|
unless layout.nil?
|
@@ -61,7 +61,7 @@ module Squib
|
|
61
61
|
opts[key.to_sym] = [] if opts[key.to_sym].nil?
|
62
62
|
opts[key.to_sym][i] ||= entry[key] #don't override if it's already there
|
63
63
|
end
|
64
|
-
else
|
64
|
+
else
|
65
65
|
Squib.logger.warn ("Layout entry '#{layout}' does not exist." )
|
66
66
|
end
|
67
67
|
end
|
@@ -99,7 +99,7 @@ module Squib
|
|
99
99
|
# @api private
|
100
100
|
def fileify(opts, file_must_exist=true)
|
101
101
|
[opts[:file]].flatten.each do |file|
|
102
|
-
if file_must_exist and !File.exists?(file)
|
102
|
+
if file_must_exist and !File.exists?(file)
|
103
103
|
raise "File #{File.expand_path(file)} does not exist!"
|
104
104
|
end
|
105
105
|
end
|
@@ -112,9 +112,9 @@ module Squib
|
|
112
112
|
def dirify(opts, key, allow_create=false)
|
113
113
|
return opts if Dir.exists?(opts[key])
|
114
114
|
if allow_create
|
115
|
-
Squib.logger.warn
|
115
|
+
Squib.logger.warn("Dir '#{opts[key]}' does not exist, creating it.")
|
116
116
|
Dir.mkdir opts[key]
|
117
|
-
return opts
|
117
|
+
return opts
|
118
118
|
else
|
119
119
|
raise "'#{opts[key]}' does not exist!"
|
120
120
|
end
|
@@ -145,14 +145,14 @@ module Squib
|
|
145
145
|
opts[:font][i] = Squib::SYSTEM_DEFAULTS[:default_font] if font == :default
|
146
146
|
end
|
147
147
|
Squib.logger.debug {"After fontify: #{opts}"}
|
148
|
-
opts
|
148
|
+
opts
|
149
149
|
end
|
150
|
-
module_function :fontify
|
150
|
+
module_function :fontify
|
151
151
|
|
152
152
|
# :nodoc:
|
153
153
|
# @api private
|
154
154
|
def radiusify(opts)
|
155
|
-
opts[:radius].each_with_index do |radius, i|
|
155
|
+
opts[:radius].each_with_index do |radius, i|
|
156
156
|
unless radius.nil?
|
157
157
|
opts[:x_radius][i] = radius
|
158
158
|
opts[:y_radius][i] = radius
|
@@ -191,4 +191,4 @@ module Squib
|
|
191
191
|
module_function :svgidify
|
192
192
|
|
193
193
|
end
|
194
|
-
end
|
194
|
+
end
|
data/lib/squib/progress.rb
CHANGED
@@ -23,16 +23,16 @@ module Squib
|
|
23
23
|
@enabled = enabled
|
24
24
|
end
|
25
25
|
|
26
|
-
def start(title=
|
26
|
+
def start(title='', total=100, &block)
|
27
27
|
if @enabled
|
28
|
-
@bar = ProgressBar.create(title: title, total: total, format: '%t <%B> %p%% %a')
|
28
|
+
@bar = ProgressBar.create(title: title, total: total, format: '%t <%B> %p%% %a')
|
29
29
|
yield(@bar)
|
30
30
|
@bar.finish
|
31
|
-
else
|
31
|
+
else
|
32
32
|
yield(Squib::DoNothing.new)
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
37
|
|
38
|
-
end
|
38
|
+
end
|
data/lib/squib/version.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module Squib
|
2
2
|
|
3
3
|
# The next version to be released.
|
4
|
-
# Uses semantic versioning
|
5
|
-
|
4
|
+
# Uses semantic versioning: http://semver.org/
|
5
|
+
#
|
6
|
+
# Most of the time this is in the alpha of the next release.
|
7
|
+
# e.g. v0.0.5a is on its way to becoming v0.0.5
|
8
|
+
#
|
9
|
+
VERSION = '0.0.5'
|
6
10
|
end
|
data/samples/autoscale_font.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'squib'
|
2
2
|
|
3
|
-
# Here's an exmaple of being able to scale a font
|
4
|
-
# based on the length of individual string.
|
3
|
+
# Here's an exmaple of being able to scale a font
|
4
|
+
# based on the length of individual string.
|
5
5
|
# Handy for making minor font scales to fill text boxes.
|
6
6
|
def autoscale(str_array)
|
7
7
|
str_array.inject([]) do | memo, str |
|
@@ -21,7 +21,7 @@ Squib::Deck.new(cards: 3) do
|
|
21
21
|
|
22
22
|
title = %w(ShortBig Medium_Length_Name Super_Duper_Long_Name)
|
23
23
|
text str: title, x: 65, y: 400, align: :center, width: 700,
|
24
|
-
font: 'Arial', font_size: autoscale(title), hint: :red
|
24
|
+
font: 'Arial', font_size: autoscale(title), hint: :red
|
25
25
|
|
26
26
|
save prefix: 'autoscale_', format: :png
|
27
|
-
end
|
27
|
+
end
|