squib 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +14 -0
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG.md +201 -175
  5. data/Gemfile +2 -4
  6. data/README.md +650 -645
  7. data/RELEASE TODO.md +18 -18
  8. data/Rakefile +106 -99
  9. data/appveyor.yml +29 -0
  10. data/lib/squib.rb +32 -32
  11. data/lib/squib/api/background.rb +20 -20
  12. data/lib/squib/api/data.rb +131 -131
  13. data/lib/squib/api/image.rb +108 -90
  14. data/lib/squib/api/save.rb +151 -149
  15. data/lib/squib/api/settings.rb +35 -35
  16. data/lib/squib/api/shapes.rb +255 -230
  17. data/lib/squib/api/text.rb +65 -65
  18. data/lib/squib/api/text_embed.rb +96 -96
  19. data/lib/squib/args/arg_loader.rb +138 -138
  20. data/lib/squib/args/box.rb +54 -54
  21. data/lib/squib/args/card_range.rb +32 -32
  22. data/lib/squib/args/color_validator.rb +11 -11
  23. data/lib/squib/args/coords.rb +32 -32
  24. data/lib/squib/args/dir_validator.rb +16 -16
  25. data/lib/squib/args/draw.rb +92 -92
  26. data/lib/squib/args/embed_adjust.rb +25 -25
  27. data/lib/squib/args/embed_key.rb +17 -17
  28. data/lib/squib/args/hand_special.rb +37 -37
  29. data/lib/squib/args/import.rb +39 -39
  30. data/lib/squib/args/input_file.rb +37 -37
  31. data/lib/squib/args/paint.rb +43 -43
  32. data/lib/squib/args/paragraph.rb +116 -115
  33. data/lib/squib/args/save_batch.rb +63 -60
  34. data/lib/squib/args/scale_box.rb +53 -53
  35. data/lib/squib/args/sheet.rb +72 -72
  36. data/lib/squib/args/showcase_special.rb +38 -38
  37. data/lib/squib/args/svg_special.rb +37 -37
  38. data/lib/squib/args/transform.rb +60 -24
  39. data/lib/squib/args/typographer.rb +117 -117
  40. data/lib/squib/card.rb +66 -67
  41. data/lib/squib/conf.rb +131 -117
  42. data/lib/squib/constants.rb +12 -178
  43. data/lib/squib/deck.rb +113 -113
  44. data/lib/squib/graphics/cairo_context_wrapper.rb +113 -99
  45. data/lib/squib/graphics/gradient_regex.rb +46 -46
  46. data/lib/squib/graphics/hand.rb +42 -42
  47. data/lib/squib/graphics/image.rb +103 -76
  48. data/lib/squib/graphics/save_doc.rb +103 -103
  49. data/lib/squib/graphics/save_images.rb +39 -33
  50. data/lib/squib/graphics/shapes.rb +135 -119
  51. data/lib/squib/graphics/showcase.rb +85 -85
  52. data/lib/squib/graphics/text.rb +176 -176
  53. data/lib/squib/layout_parser.rb +91 -91
  54. data/lib/squib/layouts/economy.yml +85 -85
  55. data/lib/squib/layouts/fantasy.yml +101 -101
  56. data/lib/squib/layouts/hand.yml +62 -62
  57. data/lib/squib/layouts/playing-card.yml +35 -35
  58. data/lib/squib/layouts/tuck_box.yml +45 -45
  59. data/lib/squib/project_template/IDEAS.md +22 -0
  60. data/lib/squib/project_template/PLAYTESTING.md +26 -0
  61. data/lib/squib/project_template/RULES.md +21 -0
  62. data/lib/squib/project_template/config.yml +49 -45
  63. data/lib/squib/sample_helpers.rb +34 -0
  64. data/lib/squib/version.rb +10 -10
  65. data/samples/autoscale_font/_autoscale_font.rb +29 -0
  66. data/samples/color_shortcuts.rb +6 -6
  67. data/samples/csv_import.rb +26 -26
  68. data/samples/custom-config.yml +5 -5
  69. data/samples/custom_config.rb +18 -18
  70. data/samples/draw_shapes.rb +48 -45
  71. data/samples/embed_text.rb +88 -88
  72. data/samples/excel.rb +55 -55
  73. data/samples/hand.rb +24 -24
  74. data/samples/images/_images.rb +104 -0
  75. data/samples/intro/01_hello.rb +9 -0
  76. data/samples/intro/02_options.rb +15 -0
  77. data/samples/intro/03_layout.rb +12 -0
  78. data/samples/intro/04_arrays.rb +16 -0
  79. data/samples/intro/05_excel.rb +15 -0
  80. data/samples/layouts.rb +62 -62
  81. data/samples/layouts_builtin.rb +51 -51
  82. data/samples/load_images.rb +99 -78
  83. data/samples/load_images_config.yml +1 -0
  84. data/samples/quantity_explosion.csv +2 -2
  85. data/samples/ranges.rb +64 -64
  86. data/samples/sample.csv +2 -2
  87. data/samples/saves.rb +9 -1
  88. data/samples/sprites.png +0 -0
  89. data/samples/text/_text.rb +46 -0
  90. data/samples/text_options.rb +102 -102
  91. data/spec/api/api_data_spec.rb +117 -117
  92. data/spec/api/api_settings_spec.rb +37 -37
  93. data/spec/args/box_spec.rb +127 -127
  94. data/spec/args/draw_spec.rb +101 -95
  95. data/spec/args/embed_key_spec.rb +13 -13
  96. data/spec/args/input_file_spec.rb +21 -21
  97. data/spec/args/paint_spec.rb +21 -21
  98. data/spec/args/paragraph_spec.rb +152 -152
  99. data/spec/args/range_spec.rb +40 -40
  100. data/spec/args/save_batch_spec.rb +51 -51
  101. data/spec/args/scale_box_spec.rb +71 -71
  102. data/spec/args/sheet_spec.rb +58 -58
  103. data/spec/args/showcase_special_spec.rb +15 -15
  104. data/spec/args/transform_spec.rb +25 -0
  105. data/spec/card_spec.rb +11 -0
  106. data/spec/conf_spec.rb +13 -3
  107. data/spec/data/conf/unrecognized.yml +4 -0
  108. data/spec/data/csv/qty.csv +2 -2
  109. data/spec/data/csv/qty_named.csv +2 -2
  110. data/spec/data/csv/with_spaces.csv +2 -2
  111. data/spec/data/samples/autoscale_font.rb.txt +84 -84
  112. data/spec/data/samples/basic.rb.txt +227 -209
  113. data/spec/data/samples/config_text_markup.rb.txt +72 -72
  114. data/spec/data/samples/csv_import.rb.txt +213 -213
  115. data/spec/data/samples/custom_config.rb.txt +57 -48
  116. data/spec/data/samples/draw_shapes.rb.txt +555 -3
  117. data/spec/data/samples/embed_text.rb.txt +283 -283
  118. data/spec/data/samples/excel.rb.txt +661 -661
  119. data/spec/data/samples/gradients.rb.txt +77 -79
  120. data/spec/data/samples/hand.rb.txt +538 -538
  121. data/spec/data/samples/hello_world.rb.txt +36 -36
  122. data/spec/data/samples/load_images.rb.txt +170 -0
  123. data/spec/data/samples/portrait-landscape.rb.txt +51 -49
  124. data/spec/data/samples/ranges.rb.txt +472 -460
  125. data/spec/data/samples/saves.rb.txt +810 -801
  126. data/spec/data/samples/showcase.rb.txt +5926 -5910
  127. data/spec/data/samples/text_options.rb.txt +1125 -1125
  128. data/spec/data/samples/tgc_proofs.rb.txt +95 -81
  129. data/spec/graphics/cairo_context_wrapper_spec.rb +104 -84
  130. data/spec/graphics/graphics_save_doc_spec.rb +67 -67
  131. data/spec/samples/diff-with-css.example.html +39 -0
  132. data/spec/samples/expected/load_images_00.png +0 -0
  133. data/spec/samples/expected/shape_00.png +0 -0
  134. data/spec/samples/run_samples_spec.rb +17 -0
  135. data/spec/samples/samples_regression_spec.rb +72 -82
  136. data/spec/spec_helper.rb +9 -1
  137. data/squib.gemspec +49 -48
  138. data/squib.sublime-project +42 -42
  139. metadata +94 -48
  140. data/spec/graphics/graphics_images_spec.rb +0 -94
@@ -1,18 +1,18 @@
1
- Be sure to remember to do the following for releases. (Copy into a GitHub issue)
2
-
3
- - [ ] CHANGELOG is written for all new changes
4
- - [ ] README is updated
5
- - [ ] Samples are updated
6
- - [ ] `rake doc`
7
- - [ ] Check `sample_regression_spec.rb` regression tests are all enabled (i.e. `overwrite_sample` is commented out)
8
- - [ ] Bump version.rb
9
- - [ ] Do a full rake locally
10
- - [ ] `rake sanity`, and check visually
11
- - [ ] Travis is passing on dev branch
12
- - [ ] Merge master branch
13
- - [ ] Create GitHub release tag
14
- - [ ] `gem push pkg/squib-x.y.z.gem`
15
- - [ ] Github milestone closed
16
- - [ ] Push `rake doc` to website
17
- - [ ] Bump version.rb to the next alpha
18
- - [ ] Publish on BoardGameGeek thread
1
+ Be sure to remember to do the following for releases. (Copy into a GitHub issue)
2
+
3
+ - [ ] CHANGELOG is written for all new changes
4
+ - [ ] README is updated
5
+ - [ ] Samples are updated
6
+ - [ ] `rake doc`
7
+ - [ ] Check `sample_regression_spec.rb` regression tests are all enabled (i.e. `overwrite_sample` is commented out)
8
+ - [ ] Bump version.rb
9
+ - [ ] Do a full rake locally
10
+ - [ ] `rake sanity`, and check visually
11
+ - [ ] Travis is passing on dev branch
12
+ - [ ] Merge master branch
13
+ - [ ] Create GitHub release tag
14
+ - [ ] `gem push pkg/squib-x.y.z.gem`
15
+ - [ ] Github milestone closed
16
+ - [ ] Push `rake doc` to website
17
+ - [ ] Bump version.rb to the next alpha
18
+ - [ ] Publish on BoardGameGeek thread
data/Rakefile CHANGED
@@ -1,99 +1,106 @@
1
- require 'bundler/gem_tasks'
2
- require 'rspec/core/rake_task'
3
- require 'yard'
4
- require 'benchmark'
5
- require 'byebug'
6
-
7
- task default: [:install, :spec]
8
-
9
- # Useful for hooking up with SublimeText.
10
- # e.g. rake sample[basic.rb]
11
- task :run,[:file] => :install do |t, args|
12
- args.with_defaults(file: 'basic.rb')
13
- Dir.chdir('samples') do
14
- args[:file] << ".rb" unless args[:file].end_with? '.rb'
15
- puts "Running samples/#{args[:file]}"
16
- load args[:file]
17
- end
18
- end
19
-
20
-
21
- RSpec::Core::RakeTask.new(:spec)
22
-
23
- RSpec::Core::RakeTask.new(:spec_fastonly) do |t|
24
- t.rspec_opts = "--tag ~slow"
25
- end
26
-
27
- task doc: [:yarddoc, :apply_google_analytics]
28
-
29
- YARD::Rake::YardocTask.new(:yarddoc) do |t|
30
- t.files = ['lib/**/*.rb', 'samples/**/*.rb'] # optional
31
- #t.options = ['--any', '--extra', '--opts'] # optional
32
- end
33
-
34
- task benchmark: [:install] do
35
- require 'squib'
36
- Squib::logger.level = Logger::ERROR #silence warnings
37
- Dir.chdir('benchmarks') do
38
- Benchmark.bm(15) do |bm|
39
- Dir['*.rb'].each do | script |
40
- GC.start
41
- bm.report(script) { load script }
42
- end
43
- end
44
- end
45
- end
46
-
47
- task :sanity_only do
48
- require_relative 'spec/samples/sanity.rb'
49
- Sanity.new.run
50
- end
51
-
52
- task sanity: [:install, :spec, :sanity_only]
53
-
54
- task :apply_google_analytics do
55
- # The string to replace in the html document. This is chosen to be the end
56
- # body </body> tag. So the script can be injected as the last thing in the
57
- # document body.
58
- string_to_replace = "</body>"
59
- # This is the string to replace with. It include the google analytics script
60
- # as well as the end </body> tag.
61
- string_to_replace_with = <<-EOF
62
- <script>
63
- (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
64
- (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
65
- m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
66
- })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
67
-
68
- ga('create', 'UA-54811605-1', 'auto');
69
- ga('send', 'pageview');
70
-
71
- </script>
72
- </body>
73
- EOF
74
-
75
- files = Dir.glob("doc/**/*.html")
76
-
77
- files.each do |html_file|
78
- puts "Processing file: #{html_file}"
79
- contents = ""
80
- # Read the file contents
81
- file = File.open(html_file)
82
- file.each { |line| contents << line }
83
- file.close
84
-
85
- # If the file already has google analytics tracking info, skip it.
86
- if contents.include?(string_to_replace_with)
87
- puts "Skipped..."
88
- next
89
- end
90
-
91
- # Apply google analytics tracking info to the html file
92
- contents.gsub!(string_to_replace, string_to_replace_with)
93
-
94
- # Write the contents with the google analytics info to the file
95
- file = File.open(html_file, "w")
96
- file.write(contents)
97
- file.close
98
- end
99
- end
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'yard'
4
+ require 'benchmark'
5
+ # require 'byebug'
6
+
7
+ desc 'install + spec'
8
+ task default: [:install, :spec]
9
+
10
+ # Useful for hooking up with SublimeText.
11
+ # e.g. rake sample[basic.rb]
12
+ desc 'Run a specific sample'
13
+ task :run,[:file] => :install do |t, args|
14
+ args.with_defaults(file: 'basic.rb')
15
+ Dir.chdir('samples') do
16
+ args[:file] << ".rb" unless args[:file].end_with? '.rb'
17
+ puts "Running samples/#{args[:file]}"
18
+ load args[:file]
19
+ end
20
+ end
21
+
22
+
23
+ RSpec::Core::RakeTask.new(:spec)
24
+
25
+ RSpec::Core::RakeTask.new(:spec_fastonly) do |t|
26
+ t.rspec_opts = "--tag ~slow"
27
+ end
28
+
29
+ desc 'Build API docs'
30
+ task doc: [:yarddoc, :apply_google_analytics]
31
+
32
+ YARD::Rake::YardocTask.new(:yarddoc) do |t|
33
+ t.files = ['lib/**/*.rb', 'samples/**/*.rb'] # optional
34
+ #t.options = ['--any', '--extra', '--opts'] # optional
35
+ end
36
+
37
+ desc 'Run some performance benchmarks'
38
+ task benchmark: [:install] do
39
+ require 'squib'
40
+ Squib::logger.level = Logger::ERROR #silence warnings
41
+ Dir.chdir('benchmarks') do
42
+ Benchmark.bm(15) do |bm|
43
+ Dir['*.rb'].each do | script |
44
+ GC.start
45
+ bm.report(script) { load script }
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ desc 'Run sanity tests without a full rebuild'
52
+ task :sanity_only do
53
+ require_relative 'spec/samples/sanity.rb'
54
+ Sanity.new.run
55
+ end
56
+
57
+ desc 'Run full rebuild with sanity tests'
58
+ task sanity: [:install, :spec, :sanity_only]
59
+
60
+ desc 'Insert Google Analytics into documentation build'
61
+ task :apply_google_analytics do
62
+ # The string to replace in the html document. This is chosen to be the end
63
+ # body </body> tag. So the script can be injected as the last thing in the
64
+ # document body.
65
+ string_to_replace = "</body>"
66
+ # This is the string to replace with. It include the google analytics script
67
+ # as well as the end </body> tag.
68
+ string_to_replace_with = <<-EOF
69
+ <script>
70
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
71
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
72
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
73
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
74
+
75
+ ga('create', 'UA-54811605-1', 'auto');
76
+ ga('send', 'pageview');
77
+
78
+ </script>
79
+ </body>
80
+ EOF
81
+
82
+ files = Dir.glob("doc/**/*.html")
83
+
84
+ files.each do |html_file|
85
+ puts "Processing file: #{html_file}"
86
+ contents = ""
87
+ # Read the file contents
88
+ file = File.open(html_file)
89
+ file.each { |line| contents << line }
90
+ file.close
91
+
92
+ # If the file already has google analytics tracking info, skip it.
93
+ if contents.include?(string_to_replace_with)
94
+ puts "Skipped..."
95
+ next
96
+ end
97
+
98
+ # Apply google analytics tracking info to the html file
99
+ contents.gsub!(string_to_replace, string_to_replace_with)
100
+
101
+ # Write the contents with the google analytics info to the file
102
+ file = File.open(html_file, "w")
103
+ file.write(contents)
104
+ file.close
105
+ end
106
+ end
@@ -0,0 +1,29 @@
1
+ version: '{build}'
2
+
3
+ skip_tags: true
4
+
5
+ environment:
6
+ matrix:
7
+ - ruby_version: "200"
8
+ - ruby_version: "200-x64"
9
+ - ruby_version: "21"
10
+ - ruby_version: "21-x64"
11
+ - ruby_version: "22"
12
+ - ruby_version: "22-x64"
13
+
14
+ install:
15
+ - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
16
+ - ruby --version
17
+ - gem --version
18
+ - gem install bundler --quiet --no-ri --no-rdoc
19
+ - bundler --version
20
+ - bundle install
21
+ - git submodule update --init --recursive
22
+
23
+ test_script:
24
+ - rake
25
+
26
+ artifacts:
27
+ - path: pkg\*.gem
28
+
29
+ build: off
@@ -1,32 +1,32 @@
1
- require 'logger'
2
- require 'cairo'
3
- require 'pango'
4
- require 'rsvg2'
5
- require 'squib/version'
6
- require 'squib/commands/new'
7
- require 'squib/deck'
8
- require 'squib/card'
9
-
10
- module Squib
11
-
12
- # Access the internal logger that Squib uses. By default, Squib configure the logger to the WARN level
13
- # Use this to suppress or increase output levels.
14
- # @example
15
- # Squib.logger.level = Logger::DEBUG #show waaaay more information than you probably need, unless you're a dev
16
- # Squib.logger.level = Logger::ERROR #basically turns it off
17
- #
18
- # @return [Logger] the ruby logger
19
- # @api public
20
- def logger
21
- if @logger.nil?
22
- @logger = Logger.new($stdout)
23
- @logger.level = Logger::WARN
24
- @logger.formatter = proc do |severity, datetime, m_progname, msg|
25
- "#{datetime} #{severity}: #{msg}\n"
26
- end
27
- end
28
- @logger
29
- end
30
- module_function :logger
31
-
32
- end
1
+ require 'logger'
2
+ require 'cairo'
3
+ require 'pango'
4
+ require 'rsvg2'
5
+ require 'squib/version'
6
+ require 'squib/commands/new'
7
+ require 'squib/deck'
8
+ require 'squib/card'
9
+
10
+ module Squib
11
+
12
+ # Access the internal logger that Squib uses. By default, Squib configure the logger to the WARN level
13
+ # Use this to suppress or increase output levels.
14
+ # @example
15
+ # Squib.logger.level = Logger::DEBUG #show waaaay more information than you probably need, unless you're a dev
16
+ # Squib.logger.level = Logger::ERROR #basically turns it off
17
+ #
18
+ # @return [Logger] the ruby logger
19
+ # @api public
20
+ def logger
21
+ if @logger.nil?
22
+ @logger = Logger.new($stdout)
23
+ @logger.level = Logger::WARN
24
+ @logger.formatter = proc do |severity, datetime, m_progname, msg|
25
+ "#{datetime} #{severity}: #{msg}\n"
26
+ end
27
+ end
28
+ @logger
29
+ end
30
+ module_function :logger
31
+
32
+ end
@@ -1,20 +1,20 @@
1
- module Squib
2
- class Deck
3
- # Fills the background with the given color
4
- # @example
5
- # background color: :white
6
- #
7
- # Options support Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
8
- #
9
- # @option opts range [Enumerable] (:all) the range of cards over which this will be rendered. See {file:README.md#Specifying_Ranges Specifying Ranges}
10
- # @option opts color [String] (:black) the color the font will render to. See {file:README.md#Specifying_Colors___Gradients Specifying Colors & Gradients}.
11
- # @return [nil] nothing
12
- # @api public
13
- def background(opts = {})
14
- range = Args::CardRange.new(opts[:range], deck_size: size)
15
- draw = Args::Draw.new(custom_colors).load!(opts, expand_by: size, layout: layout, dpi: dpi)
16
- range.each { |i| @cards[i].background(draw.color[i]) }
17
- end
18
-
19
- end
20
- end
1
+ module Squib
2
+ class Deck
3
+ # Fills the background with the given color
4
+ # @example
5
+ # background color: :white
6
+ #
7
+ # Options support Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
8
+ #
9
+ # @option opts range [Enumerable] (:all) the range of cards over which this will be rendered. See {file:README.md#Specifying_Ranges Specifying Ranges}
10
+ # @option opts color [String] (:black) the color the font will render to. See {file:README.md#Specifying_Colors___Gradients Specifying Colors & Gradients}.
11
+ # @return [nil] nothing
12
+ # @api public
13
+ def background(opts = {})
14
+ range = Args::CardRange.new(opts[:range], deck_size: size)
15
+ draw = Args::Draw.new(custom_colors).load!(opts, expand_by: size, layout: layout, dpi: dpi)
16
+ range.each { |i| @cards[i].background(draw.color[i]) }
17
+ end
18
+
19
+ end
20
+ end
@@ -1,131 +1,131 @@
1
- require 'roo'
2
- require 'csv'
3
- require 'squib/args/input_file'
4
- require 'squib/args/import'
5
-
6
- module Squib
7
-
8
- # Pulls Excel data from `.xlsx` files into a column-based hash
9
- #
10
- # Pulls the data into a Hash of arrays based on the columns. First row is assumed to be the header row.
11
- # See the example `samples/excel.rb` in the [source repository](https://github.com/andymeneely/squib/tree/master/samples)
12
- #
13
- # @example
14
- # # Excel file looks like this:
15
- # # | h1 | h2 |
16
- # # ------------
17
- # # | 1 | 2 |
18
- # # | 3 | 4 |
19
- # data = xlsx file: 'data.xlsx', sheet: 0
20
- # => {'h1' => [1,3], 'h2' => [2,4]}
21
- #
22
- # @option opts file [String] the file to open. Must end in `.xlsx`. Opens relative to the current directory.
23
- # @option opts sheet [Integer] (0) The zero-based index of the sheet from which to read.
24
- # @option opts strip [Boolean] (true) When true, strips leading and trailing whitespace on values and headers
25
- # @option opts explode [String] ('qty') Quantity explosion will be applied to the column this name. See README for example.
26
- # @return [Hash] a hash of arrays based on columns in the spreadsheet
27
- # @api public
28
- def xlsx(opts = {})
29
- input = Args::InputFile.new(file: 'deck.xlsx').load!(opts)
30
- import = Args::Import.new.load!(opts)
31
- s = Roo::Excelx.new(input.file[0])
32
- s.default_sheet = s.sheets[input.sheet[0]]
33
- data = {}
34
- s.first_column.upto(s.last_column) do |col|
35
- header = s.cell(s.first_row,col).to_s
36
- header.strip! if import.strip?
37
- data[header] = []
38
- (s.first_row + 1).upto(s.last_row) do |row|
39
- cell = s.cell(row,col)
40
- # Roo hack for avoiding unnecessary .0's on whole integers (https://github.com/roo-rb/roo/issues/139)
41
- cell = s.excelx_value(row,col) if s.excelx_type(row,col) == [:numeric_or_formula, 'General']
42
- cell.strip! if cell.respond_to?(:strip) && import.strip?
43
- cell = yield(header, cell) if block_given?
44
- data[header] << cell
45
- end#row
46
- end#col
47
- explode_quantities(data, import.explode)
48
- end#xlsx
49
- module_function :xlsx
50
-
51
- # Pulls CSV data from `.csv` files into a column-based hash
52
- #
53
- # Pulls the data into a Hash of arrays based on the columns. First row is assumed to be the header row.
54
- # See the example `samples/csv.rb` in the [source repository](https://github.com/andymeneely/squib/tree/master/samples)
55
- #
56
- # @example
57
- # # File data.csv looks like this (without the comment symbols)
58
- # # h1,h2
59
- # # 1,2
60
- # # 3,4
61
- # data = csv file: 'data.csv'
62
- # => {'h1' => [1,3], 'h2' => [2,4]}
63
- #
64
- # Parsing uses Ruby's CSV, with options `{headers: true, converters: :numeric}`
65
- # http://www.ruby-doc.org/stdlib-2.0/libdoc/csv/rdoc/CSV.html
66
- #
67
- # @option opts file [String] the CSV-formatted file to open. Opens relative to the current directory.
68
- # @option opts strip [Boolean] (true) When true, strips leading and trailing whitespace on values and headers
69
- # @option opts explode [String] ('qty') Quantity explosion will be applied to the column this name. See README for example.
70
- # @return [Hash] a hash of arrays based on columns in the table
71
- # @api public
72
- def csv(opts = {})
73
- file = Args::InputFile.new(file: 'deck.csv').load!(opts).file[0]
74
- import = Args::Import.new.load!(opts)
75
- table = CSV.read(file, headers: true, converters: :numeric)
76
- check_duplicate_csv_headers(table)
77
- hash = Hash.new
78
- table.headers.each do |header|
79
- new_header = header.to_s
80
- new_header = new_header.strip if import.strip?
81
- hash[new_header] ||= table[header]
82
- end
83
- if import.strip?
84
- new_hash = Hash.new
85
- hash.each do |header, col|
86
- new_hash[header] = col.map { |str| str = str.strip if str.respond_to?(:strip); str }
87
- end
88
- hash = new_hash
89
- end
90
- return explode_quantities(hash, import.explode)
91
- end
92
- module_function :csv
93
-
94
- # Check if the given CSV table has duplicate columns, and throw a warning
95
- # @api private
96
- def check_duplicate_csv_headers(table)
97
- if table.headers.size != table.headers.uniq.size
98
- dups = table.headers.select{|e| table.headers.count(e) > 1 }
99
- Squib.logger.warn "CSV duplicated the following column keys: #{dups.join(',')}"
100
- end
101
- end
102
- module_function :check_duplicate_csv_headers
103
-
104
- def explode_quantities(data, qty)
105
- return data unless data.key? qty.to_s.strip
106
- qtys = data[qty]
107
- new_data = {}
108
- data.each do |col, arr|
109
- new_data[col] = []
110
- qtys.each_with_index do |qty, index|
111
- qty.to_i.times { new_data[col] << arr[index] }
112
- end
113
- end
114
- return new_data
115
- end
116
- module_function :explode_quantities
117
-
118
- class Deck
119
-
120
- # Convenience call on deck goes to the module function
121
- def xlsx(opts = {})
122
- Squib.xlsx(opts)
123
- end
124
-
125
- # Convenience call on deck goes to the module function
126
- def csv(opts = {})
127
- Squib.csv(opts)
128
- end
129
-
130
- end
131
- end
1
+ require 'roo'
2
+ require 'csv'
3
+ require 'squib/args/input_file'
4
+ require 'squib/args/import'
5
+
6
+ module Squib
7
+
8
+ # Pulls Excel data from `.xlsx` files into a column-based hash
9
+ #
10
+ # Pulls the data into a Hash of arrays based on the columns. First row is assumed to be the header row.
11
+ # See the example `samples/excel.rb` in the [source repository](https://github.com/andymeneely/squib/tree/master/samples)
12
+ #
13
+ # @example
14
+ # # Excel file looks like this:
15
+ # # | h1 | h2 |
16
+ # # ------------
17
+ # # | 1 | 2 |
18
+ # # | 3 | 4 |
19
+ # data = xlsx file: 'data.xlsx', sheet: 0
20
+ # => {'h1' => [1,3], 'h2' => [2,4]}
21
+ #
22
+ # @option opts file [String] the file to open. Must end in `.xlsx`. Opens relative to the current directory.
23
+ # @option opts sheet [Integer] (0) The zero-based index of the sheet from which to read.
24
+ # @option opts strip [Boolean] (true) When true, strips leading and trailing whitespace on values and headers
25
+ # @option opts explode [String] ('qty') Quantity explosion will be applied to the column this name. See README for example.
26
+ # @return [Hash] a hash of arrays based on columns in the spreadsheet
27
+ # @api public
28
+ def xlsx(opts = {})
29
+ input = Args::InputFile.new(file: 'deck.xlsx').load!(opts)
30
+ import = Args::Import.new.load!(opts)
31
+ s = Roo::Excelx.new(input.file[0])
32
+ s.default_sheet = s.sheets[input.sheet[0]]
33
+ data = {}
34
+ s.first_column.upto(s.last_column) do |col|
35
+ header = s.cell(s.first_row,col).to_s
36
+ header.strip! if import.strip?
37
+ data[header] = []
38
+ (s.first_row + 1).upto(s.last_row) do |row|
39
+ cell = s.cell(row,col)
40
+ # Roo hack for avoiding unnecessary .0's on whole integers (https://github.com/roo-rb/roo/issues/139)
41
+ cell = s.excelx_value(row,col) if s.excelx_type(row,col) == [:numeric_or_formula, 'General']
42
+ cell.strip! if cell.respond_to?(:strip) && import.strip?
43
+ cell = yield(header, cell) if block_given?
44
+ data[header] << cell
45
+ end#row
46
+ end#col
47
+ explode_quantities(data, import.explode)
48
+ end#xlsx
49
+ module_function :xlsx
50
+
51
+ # Pulls CSV data from `.csv` files into a column-based hash
52
+ #
53
+ # Pulls the data into a Hash of arrays based on the columns. First row is assumed to be the header row.
54
+ # See the example `samples/csv.rb` in the [source repository](https://github.com/andymeneely/squib/tree/master/samples)
55
+ #
56
+ # @example
57
+ # # File data.csv looks like this (without the comment symbols)
58
+ # # h1,h2
59
+ # # 1,2
60
+ # # 3,4
61
+ # data = csv file: 'data.csv'
62
+ # => {'h1' => [1,3], 'h2' => [2,4]}
63
+ #
64
+ # Parsing uses Ruby's CSV, with options `{headers: true, converters: :numeric}`
65
+ # http://www.ruby-doc.org/stdlib-2.0/libdoc/csv/rdoc/CSV.html
66
+ #
67
+ # @option opts file [String] the CSV-formatted file to open. Opens relative to the current directory.
68
+ # @option opts strip [Boolean] (true) When true, strips leading and trailing whitespace on values and headers
69
+ # @option opts explode [String] ('qty') Quantity explosion will be applied to the column this name. See README for example.
70
+ # @return [Hash] a hash of arrays based on columns in the table
71
+ # @api public
72
+ def csv(opts = {})
73
+ file = Args::InputFile.new(file: 'deck.csv').load!(opts).file[0]
74
+ import = Args::Import.new.load!(opts)
75
+ table = CSV.read(file, headers: true, converters: :numeric)
76
+ check_duplicate_csv_headers(table)
77
+ hash = Hash.new
78
+ table.headers.each do |header|
79
+ new_header = header.to_s
80
+ new_header = new_header.strip if import.strip?
81
+ hash[new_header] ||= table[header]
82
+ end
83
+ if import.strip?
84
+ new_hash = Hash.new
85
+ hash.each do |header, col|
86
+ new_hash[header] = col.map { |str| str = str.strip if str.respond_to?(:strip); str }
87
+ end
88
+ hash = new_hash
89
+ end
90
+ return explode_quantities(hash, import.explode)
91
+ end
92
+ module_function :csv
93
+
94
+ # Check if the given CSV table has duplicate columns, and throw a warning
95
+ # @api private
96
+ def check_duplicate_csv_headers(table)
97
+ if table.headers.size != table.headers.uniq.size
98
+ dups = table.headers.select{|e| table.headers.count(e) > 1 }
99
+ Squib.logger.warn "CSV duplicated the following column keys: #{dups.join(',')}"
100
+ end
101
+ end
102
+ module_function :check_duplicate_csv_headers
103
+
104
+ def explode_quantities(data, qty)
105
+ return data unless data.key? qty.to_s.strip
106
+ qtys = data[qty]
107
+ new_data = {}
108
+ data.each do |col, arr|
109
+ new_data[col] = []
110
+ qtys.each_with_index do |qty, index|
111
+ qty.to_i.times { new_data[col] << arr[index] }
112
+ end
113
+ end
114
+ return new_data
115
+ end
116
+ module_function :explode_quantities
117
+
118
+ class Deck
119
+
120
+ # Convenience call on deck goes to the module function
121
+ def xlsx(opts = {})
122
+ Squib.xlsx(opts)
123
+ end
124
+
125
+ # Convenience call on deck goes to the module function
126
+ def csv(opts = {})
127
+ Squib.csv(opts)
128
+ end
129
+
130
+ end
131
+ end