squib 0.6.0 → 0.7.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.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +162 -133
  3. data/Gemfile +4 -4
  4. data/README.md +630 -550
  5. data/RELEASE TODO.md +18 -18
  6. data/Rakefile +99 -99
  7. data/lib/squib.rb +32 -32
  8. data/lib/squib/api/background.rb +20 -19
  9. data/lib/squib/api/data.rb +100 -99
  10. data/lib/squib/api/image.rb +90 -76
  11. data/lib/squib/api/save.rb +149 -103
  12. data/lib/squib/api/settings.rb +35 -37
  13. data/lib/squib/api/shapes.rb +230 -228
  14. data/lib/squib/api/text.rb +65 -66
  15. data/lib/squib/api/text_embed.rb +96 -66
  16. data/lib/squib/args/arg_loader.rb +138 -0
  17. data/lib/squib/args/box.rb +55 -0
  18. data/lib/squib/args/card_range.rb +32 -0
  19. data/lib/squib/args/color_validator.rb +12 -0
  20. data/lib/squib/args/coords.rb +33 -0
  21. data/lib/squib/args/dir_validator.rb +16 -0
  22. data/lib/squib/args/draw.rb +92 -0
  23. data/lib/squib/args/embed_adjust.rb +25 -0
  24. data/lib/squib/args/embed_key.rb +17 -0
  25. data/lib/squib/args/hand_special.rb +37 -0
  26. data/lib/squib/args/input_file.rb +37 -0
  27. data/lib/squib/args/paint.rb +44 -0
  28. data/lib/squib/args/paragraph.rb +115 -0
  29. data/lib/squib/args/save_batch.rb +60 -0
  30. data/lib/squib/args/scale_box.rb +53 -0
  31. data/lib/squib/args/sheet.rb +72 -0
  32. data/lib/squib/args/showcase_special.rb +38 -0
  33. data/lib/squib/args/svg_special.rb +37 -0
  34. data/lib/squib/args/transform.rb +25 -0
  35. data/lib/squib/args/typographer.rb +117 -117
  36. data/lib/squib/card.rb +67 -67
  37. data/lib/squib/conf.rb +117 -111
  38. data/lib/squib/constants.rb +178 -178
  39. data/lib/squib/deck.rb +113 -111
  40. data/lib/squib/graphics/cairo_context_wrapper.rb +99 -53
  41. data/lib/squib/graphics/gradient_regex.rb +46 -46
  42. data/lib/squib/graphics/hand.rb +42 -43
  43. data/lib/squib/graphics/image.rb +76 -73
  44. data/lib/squib/graphics/save_doc.rb +103 -137
  45. data/lib/squib/graphics/save_images.rb +33 -33
  46. data/lib/squib/graphics/shapes.rb +119 -152
  47. data/lib/squib/graphics/showcase.rb +85 -88
  48. data/lib/squib/graphics/text.rb +176 -216
  49. data/lib/squib/layout_parser.rb +91 -89
  50. data/lib/squib/layouts/economy.yml +85 -0
  51. data/lib/squib/layouts/fantasy.yml +101 -0
  52. data/lib/squib/layouts/hand.yml +62 -46
  53. data/lib/squib/layouts/playing-card.yml +35 -18
  54. data/lib/squib/project_template/config.yml +45 -40
  55. data/lib/squib/version.rb +10 -10
  56. data/samples/color_shortcuts.rb +6 -0
  57. data/samples/csv_import.rb +18 -18
  58. data/samples/custom-config.yml +5 -5
  59. data/samples/custom_config.rb +18 -18
  60. data/samples/draw_shapes.rb +45 -35
  61. data/samples/embed_text.rb +88 -90
  62. data/samples/hand.rb +24 -24
  63. data/samples/layouts.rb +62 -61
  64. data/samples/layouts_builtin.rb +51 -0
  65. data/samples/load_images.rb +78 -64
  66. data/samples/ranges.rb +64 -53
  67. data/samples/sample.csv +2 -2
  68. data/samples/text_options.rb +102 -94
  69. data/spec/api/api_data_spec.rb +57 -50
  70. data/spec/api/api_settings_spec.rb +37 -17
  71. data/spec/args/box_spec.rb +127 -0
  72. data/spec/args/draw_spec.rb +95 -0
  73. data/spec/args/embed_key_spec.rb +13 -0
  74. data/spec/args/input_file_spec.rb +21 -0
  75. data/spec/args/paint_spec.rb +22 -0
  76. data/spec/args/paragraph_spec.rb +153 -0
  77. data/spec/args/range_spec.rb +36 -0
  78. data/spec/args/save_batch_spec.rb +51 -0
  79. data/spec/args/scale_box_spec.rb +71 -0
  80. data/spec/args/sheet_spec.rb +58 -0
  81. data/spec/args/showcase_special_spec.rb +15 -0
  82. data/spec/data/samples/autoscale_font.rb.txt +84 -87
  83. data/spec/data/samples/basic.rb.txt +209 -203
  84. data/spec/data/samples/cairo_access.rb.txt +2 -2
  85. data/spec/data/samples/config_text_markup.rb.txt +72 -75
  86. data/spec/data/samples/csv_import.rb.txt +76 -80
  87. data/spec/data/samples/custom_config.rb.txt +48 -49
  88. data/spec/data/samples/draw_shapes.rb.txt +100 -42
  89. data/spec/data/samples/embed_text.rb.txt +283 -295
  90. data/spec/data/samples/excel.rb.txt +162 -171
  91. data/spec/data/samples/gradients.rb.txt +79 -67
  92. data/spec/data/samples/hand.rb.txt +538 -514
  93. data/spec/data/samples/hello_world.rb.txt +36 -38
  94. data/spec/data/samples/load_images.rb.txt +41 -5
  95. data/spec/data/samples/portrait-landscape.rb.txt +49 -51
  96. data/spec/data/samples/ranges.rb.txt +460 -429
  97. data/spec/data/samples/saves.rb.txt +801 -785
  98. data/spec/data/samples/showcase.rb.txt +5910 -5906
  99. data/spec/data/samples/text_options.rb.txt +1125 -981
  100. data/spec/data/samples/tgc_proofs.rb.txt +81 -79
  101. data/spec/data/samples/units.rb.txt +18 -12
  102. data/spec/data/xlsx/with_macros.xlsm +0 -0
  103. data/spec/graphics/cairo_context_wrapper_spec.rb +84 -75
  104. data/spec/graphics/graphics_images_spec.rb +94 -85
  105. data/spec/graphics/graphics_save_doc_spec.rb +67 -65
  106. data/spec/samples/expected/hand.png +0 -0
  107. data/spec/samples/expected/hand_pretty.png +0 -0
  108. data/spec/samples/expected/layout_00.png +0 -0
  109. data/spec/samples/expected/load_images_00.png +0 -0
  110. data/spec/samples/expected/ranges_00.png +0 -0
  111. data/spec/samples/expected/shape_00.png +0 -0
  112. data/spec/samples/expected/showcase.png +0 -0
  113. data/spec/samples/expected/showcase2.png +0 -0
  114. data/spec/samples/expected/showcase_individual_00.png +0 -0
  115. data/spec/samples/expected/showcase_individual_01.png +0 -0
  116. data/spec/samples/expected/showcase_individual_02.png +0 -0
  117. data/spec/samples/expected/showcase_individual_03.png +0 -0
  118. data/spec/samples/expected/text_00.png +0 -0
  119. data/spec/samples/expected/text_01.png +0 -0
  120. data/spec/samples/expected/text_02.png +0 -0
  121. data/spec/samples/samples_regression_spec.rb +82 -82
  122. data/spec/spec_helper.rb +3 -2
  123. data/squib.gemspec +48 -48
  124. data/squib.sublime-project +42 -36
  125. metadata +61 -33
  126. data/lib/squib/input_helpers.rb +0 -238
  127. data/spec/api/api_image_spec.rb +0 -38
  128. data/spec/api/api_text_spec.rb +0 -37
  129. data/spec/graphics/graphics_shapes_spec.rb +0 -85
  130. data/spec/graphics/graphics_text_spec.rb +0 -164
  131. data/spec/input_helpers_spec.rb +0 -238
  132. data/spec/samples/expected/embed_multi_00.png +0 -0
  133. data/spec/samples/expected/embed_multi_01.png +0 -0
  134. data/spec/samples/expected/embed_multi_02.png +0 -0
  135. data/spec/samples/expected/ranges_01.png +0 -0
  136. data/spec/samples/expected/ranges_02.png +0 -0
@@ -0,0 +1,60 @@
1
+ require 'squib/args/arg_loader'
2
+ require 'squib/args/dir_validator'
3
+
4
+ module Squib
5
+ # @api private
6
+ module Args
7
+ class SaveBatch
8
+ include ArgLoader
9
+ include DirValidator
10
+
11
+ def initialize
12
+ end
13
+
14
+ def self.parameters
15
+ { dir: '_output',
16
+ prefix: 'card_',
17
+ count_format: '%02d',
18
+ rotate: false,
19
+ angle: 0,
20
+ }
21
+ end
22
+
23
+ def self.expanding_parameters
24
+ self.parameters.keys # all of them
25
+ end
26
+
27
+ def self.params_with_units
28
+ [] # none of them
29
+ end
30
+
31
+ def validate_dir(arg, _i)
32
+ ensure_dir_created(arg)
33
+ end
34
+
35
+ def validate_rotate(arg, i)
36
+ case arg
37
+ when true, :clockwise
38
+ angle[i] = 0.5 * Math::PI
39
+ return true
40
+ when :counterclockwise
41
+ angle[i] = 1.5 * Math::PI
42
+ return true
43
+ when false
44
+ false
45
+ else
46
+ raise 'invalid option to rotate: only [true, false, :clockwise, :counterclockwise]'
47
+ end
48
+ end
49
+
50
+ def full_filename(i)
51
+ "#{dir[i]}/#{prefix[i]}#{count_format[i] % i}.png"
52
+ end
53
+
54
+ def summary
55
+ "#{dir[0]}/#{prefix[0]}_*"
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,53 @@
1
+ require 'squib/args/arg_loader'
2
+
3
+ module Squib
4
+ # @api private
5
+ module Args
6
+
7
+ class ScaleBox
8
+ include ArgLoader
9
+
10
+ def initialize(deck)
11
+ @deck = deck
12
+ end
13
+
14
+ def self.parameters
15
+ { x: 0, y: 0,
16
+ width: :native, height: :native
17
+ }
18
+ end
19
+
20
+ def self.expanding_parameters
21
+ parameters.keys # all of them
22
+ end
23
+
24
+ def self.params_with_units
25
+ parameters.keys # all of them
26
+ end
27
+
28
+ def validate_width(arg, i)
29
+ return @deck.width if arg.to_s == 'deck'
30
+ return :native if arg.to_s == 'native'
31
+ return arg if arg.respond_to? :to_f
32
+ if arg.to_s == 'scale'
33
+ raise 'if width is :scale, height must be a number' unless height[i].respond_to? :to_f
34
+ return arg
35
+ end
36
+ raise 'width must be a number, :scale, :native, or :deck'
37
+ end
38
+
39
+ def validate_height(arg, i)
40
+ return @deck.height if arg.to_s == 'deck'
41
+ return :native if arg.to_s == 'native'
42
+ return arg if arg.respond_to? :to_f
43
+ if arg.to_s == 'scale'
44
+ raise 'if height is \'scale\', width must be a number' unless width[i].respond_to? :to_f
45
+ return arg
46
+ end
47
+ raise 'height must be a number, :scale, :native, or :deck'
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,72 @@
1
+ require 'cairo'
2
+ require 'squib/args/arg_loader'
3
+ require 'squib/args/color_validator'
4
+ require 'squib/args/dir_validator'
5
+
6
+ module Squib
7
+ # @api private
8
+ module Args
9
+
10
+ class Sheet
11
+ include ArgLoader
12
+ include ColorValidator
13
+ include DirValidator
14
+
15
+ def initialize(custom_colors = {}, dsl_method_defaults = {}, deck_size = 1)
16
+ @custom_colors = custom_colors
17
+ @dsl_method_defaults = dsl_method_defaults
18
+ @deck_size = deck_size
19
+ end
20
+
21
+ def self.parameters
22
+ {
23
+ dir: '_output',
24
+ file: 'sheet.png',
25
+ fill_color: :white,
26
+ gap: 0,
27
+ height: 2550,
28
+ margin: 75,
29
+ rows: :infinite,
30
+ columns: 5,
31
+ trim_radius: 38,
32
+ trim: 0,
33
+ width: 3300,
34
+ }
35
+ end
36
+
37
+ def self.expanding_parameters
38
+ [] # none of them
39
+ end
40
+
41
+ def self.params_with_units
42
+ [ :gap, :height, :margin, :trim_radius, :trim, :width ]
43
+ end
44
+
45
+ def validate_fill_color(arg)
46
+ colorify(arg, @custom_colors)
47
+ end
48
+
49
+ def validate_dir(arg)
50
+ ensure_dir_created(arg)
51
+ end
52
+
53
+ def validate_columns(arg)
54
+ raise 'columns must be an integer' unless arg.respond_to? :to_i
55
+ arg.to_i
56
+ end
57
+
58
+ def validate_rows(arg)
59
+ raise 'columns must be an integer' unless columns.respond_to? :to_i
60
+ return 1 if @deck_size < columns
61
+ return arg if arg.respond_to? :to_i
62
+ (@deck_size.to_i / columns.to_i).ceil
63
+ end
64
+
65
+ def full_filename
66
+ "#{dir}/#{file}"
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,38 @@
1
+ require 'cairo'
2
+ require 'squib/args/arg_loader'
3
+ require 'squib/args/dir_validator'
4
+
5
+ module Squib
6
+ # @api private
7
+ module Args
8
+
9
+ class ShowcaseSpecial
10
+ include ArgLoader
11
+ include DirValidator
12
+
13
+ def self.parameters
14
+ { scale: 0.85,
15
+ offset: 1.1,
16
+ reflect_offset: 15,
17
+ reflect_percent: 0.25,
18
+ reflect_strength: 0.2,
19
+ face: :left,
20
+ }
21
+ end
22
+
23
+ def self.expanding_parameters
24
+ [] # none of them
25
+ end
26
+
27
+ def self.params_with_units
28
+ [ :reflect_offset ]
29
+ end
30
+
31
+ def face_right?
32
+ @face.to_s.strip.downcase == 'right'
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,37 @@
1
+ require 'squib/args/arg_loader'
2
+
3
+ module Squib
4
+ # @api private
5
+ module Args
6
+
7
+ class SvgSpecial
8
+ include ArgLoader
9
+
10
+ def self.parameters
11
+ { data: nil, id: nil, force_id: false }
12
+ end
13
+
14
+ def self.expanding_parameters
15
+ parameters.keys # all of them
16
+ end
17
+
18
+ def self.params_with_units
19
+ []
20
+ end
21
+
22
+ def validate_id(arg, _i)
23
+ return nil if arg.nil?
24
+ arg = '#' << arg unless arg.start_with? '#'
25
+ arg
26
+ end
27
+
28
+ # Only render if we have an ID specified, or we are forcing an ID
29
+ def render?(i)
30
+ return false if force_id[i] && id[i].to_s.empty?
31
+ return true
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ require 'squib/args/arg_loader'
2
+
3
+ module Squib
4
+ # @api private
5
+ module Args
6
+
7
+ class Transform
8
+ include ArgLoader
9
+
10
+ def self.parameters
11
+ { angle: 0 }
12
+ end
13
+
14
+ def self.expanding_parameters
15
+ parameters.keys # all of them
16
+ end
17
+
18
+ def self.params_with_units
19
+ parameters.keys # all of them
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+ end
@@ -1,118 +1,118 @@
1
- require 'squib/constants'
2
- module Squib
3
- #@api private
4
- module Args
5
- # Internal class for handling arguments
6
- #@api private
7
- class Typographer
8
-
9
- def initialize(config = Conf::DEFAULTS)
10
- %w(lsquote ldquote rsquote rdquote smart_quotes
11
- em_dash en_dash ellipsis).each do |var|
12
- instance_variable_set("@#{var}", config[var])
13
- end
14
- end
15
-
16
- def process(str)
17
- str = explicit_replacements(str.to_s)
18
- str = smart_quotes(str) if @smart_quotes
19
- str
20
- end
21
-
22
- def explicit_replacements(str)
23
- [ :left_curly, :right_curly, :apostraphize,
24
- :ellipsificate, :em_dash, :en_dash ].each do |sym|
25
- str = each_non_tag(str) do |token|
26
- self.method(sym).call(token)
27
- end
28
- end
29
- str
30
- end
31
-
32
- def smart_quotes(str)
33
- [ :single_inside_double_quote,
34
- :right_double_quote,
35
- :left_double_quote,
36
- :right_single_quote,
37
- :left_single_quote].each do |sym|
38
- str = each_non_tag(str) do |token|
39
- self.method(sym).call(token)
40
- end
41
- end
42
- str
43
- end
44
-
45
- # Iterate over each non-tag for processing
46
- # Allows us to ignore anything inside < and >
47
- def each_non_tag(str)
48
- full_str = ''
49
- tag_delimit = /(<(?:(?!<).)*>)/ # use non-capturing group w/ negative lookahead
50
- str.split(tag_delimit).each do |token|
51
- if token.start_with? '<'
52
- full_str << token # don't process tags
53
- else
54
- full_str << yield(token)
55
- end
56
- end
57
- return full_str
58
- end
59
-
60
- # Straightforward replace
61
- def left_curly(str)
62
- str.gsub('``', @ldquote)
63
- end
64
-
65
- # Straightforward replace
66
- def right_curly(str)
67
- str.gsub(%{''}, @rdquote)
68
- end
69
-
70
- # A quote between two letters is an apostraphe
71
- def apostraphize(str)
72
- str.gsub(/(\w)(\')(\w)/, '\1' + @rsquote + '\3')
73
- end
74
-
75
- # Straightforward replace
76
- def ellipsificate(str)
77
- str.gsub('...', @ellipsis)
78
- end
79
-
80
- # Straightforward replace
81
- def en_dash(str)
82
- str.gsub('--', @en_dash)
83
- end
84
-
85
- # Straightforward replace
86
- def em_dash(str)
87
- str.gsub('---', @em_dash)
88
- end
89
-
90
- # Quote next to non-whitespace curls
91
- def right_double_quote(str)
92
- str.gsub(/(\S)(\")/, '\1' + @rdquote)
93
- end
94
-
95
- # Quote next to non-whitespace curls
96
- def left_double_quote(str)
97
- str.gsub(/(\")(\S)/, @ldquote + '\2')
98
- end
99
-
100
- # Handle the cases where a double quote is next to a single quote
101
- def single_inside_double_quote(str)
102
- str.gsub(/(\")(\')(\S)/, @ldquote + @lsquote + '\3')
103
- .gsub(/(\")(\')(\S)/, '\1' + @rsquote + @rdquote)
104
- end
105
-
106
- # Quote next to non-whitespace curls
107
- def right_single_quote(str)
108
- str.gsub(/(\S)(\')/, '\1' + @rsquote)
109
- end
110
-
111
- # Quote next to non-whitespace curls
112
- def left_single_quote(str)
113
- str.gsub(/(\')(\S)/, @lsquote + '\2')
114
- end
115
-
116
- end
117
- end
1
+ require 'squib/constants'
2
+ module Squib
3
+ #@api private
4
+ module Args
5
+ # Internal class for handling arguments
6
+ #@api private
7
+ class Typographer
8
+
9
+ def initialize(config = Conf::DEFAULTS)
10
+ %w(lsquote ldquote rsquote rdquote smart_quotes
11
+ em_dash en_dash ellipsis).each do |var|
12
+ instance_variable_set("@#{var}", config[var])
13
+ end
14
+ end
15
+
16
+ def process(str)
17
+ str = explicit_replacements(str.to_s)
18
+ str = smart_quotes(str) if @smart_quotes
19
+ str
20
+ end
21
+
22
+ def explicit_replacements(str)
23
+ [ :left_curly, :right_curly, :apostraphize,
24
+ :ellipsificate, :em_dash, :en_dash ].each do |sym|
25
+ str = each_non_tag(str) do |token|
26
+ self.method(sym).call(token)
27
+ end
28
+ end
29
+ str
30
+ end
31
+
32
+ def smart_quotes(str)
33
+ [ :single_inside_double_quote,
34
+ :right_double_quote,
35
+ :left_double_quote,
36
+ :right_single_quote,
37
+ :left_single_quote].each do |sym|
38
+ str = each_non_tag(str) do |token|
39
+ self.method(sym).call(token)
40
+ end
41
+ end
42
+ str
43
+ end
44
+
45
+ # Iterate over each non-tag for processing
46
+ # Allows us to ignore anything inside < and >
47
+ def each_non_tag(str)
48
+ full_str = ''
49
+ tag_delimit = /(<(?:(?!<).)*>)/ # use non-capturing group w/ negative lookahead
50
+ str.split(tag_delimit).each do |token|
51
+ if token.start_with? '<'
52
+ full_str << token # don't process tags
53
+ else
54
+ full_str << yield(token)
55
+ end
56
+ end
57
+ return full_str
58
+ end
59
+
60
+ # Straightforward replace
61
+ def left_curly(str)
62
+ str.gsub('``', @ldquote)
63
+ end
64
+
65
+ # Straightforward replace
66
+ def right_curly(str)
67
+ str.gsub(%{''}, @rdquote)
68
+ end
69
+
70
+ # A quote between two letters is an apostraphe
71
+ def apostraphize(str)
72
+ str.gsub(/(\w)(\')(\w)/, '\1' + @rsquote + '\3')
73
+ end
74
+
75
+ # Straightforward replace
76
+ def ellipsificate(str)
77
+ str.gsub('...', @ellipsis)
78
+ end
79
+
80
+ # Straightforward replace
81
+ def en_dash(str)
82
+ str.gsub('--', @en_dash)
83
+ end
84
+
85
+ # Straightforward replace
86
+ def em_dash(str)
87
+ str.gsub('---', @em_dash)
88
+ end
89
+
90
+ # Quote next to non-whitespace curls
91
+ def right_double_quote(str)
92
+ str.gsub(/(\S)(\")/, '\1' + @rdquote)
93
+ end
94
+
95
+ # Quote next to non-whitespace curls
96
+ def left_double_quote(str)
97
+ str.gsub(/(\")(\S)/, @ldquote + '\2')
98
+ end
99
+
100
+ # Handle the cases where a double quote is next to a single quote
101
+ def single_inside_double_quote(str)
102
+ str.gsub(/(\")(\')(\S)/, @ldquote + @lsquote + '\3')
103
+ .gsub(/(\")(\')(\S)/, '\1' + @rsquote + @rdquote)
104
+ end
105
+
106
+ # Quote next to non-whitespace curls
107
+ def right_single_quote(str)
108
+ str.gsub(/(\S)(\')/, '\1' + @rsquote)
109
+ end
110
+
111
+ # Quote next to non-whitespace curls
112
+ def left_single_quote(str)
113
+ str.gsub(/(\')(\S)/, @lsquote + '\2')
114
+ end
115
+
116
+ end
117
+ end
118
118
  end