squib 0.8.0 → 0.9.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.
- checksums.yaml +4 -4
- data/.gitmodules +14 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +201 -175
- data/Gemfile +2 -4
- data/README.md +650 -645
- data/RELEASE TODO.md +18 -18
- data/Rakefile +106 -99
- data/appveyor.yml +29 -0
- data/lib/squib.rb +32 -32
- data/lib/squib/api/background.rb +20 -20
- data/lib/squib/api/data.rb +131 -131
- data/lib/squib/api/image.rb +108 -90
- data/lib/squib/api/save.rb +151 -149
- data/lib/squib/api/settings.rb +35 -35
- data/lib/squib/api/shapes.rb +255 -230
- data/lib/squib/api/text.rb +65 -65
- data/lib/squib/api/text_embed.rb +96 -96
- data/lib/squib/args/arg_loader.rb +138 -138
- data/lib/squib/args/box.rb +54 -54
- data/lib/squib/args/card_range.rb +32 -32
- data/lib/squib/args/color_validator.rb +11 -11
- data/lib/squib/args/coords.rb +32 -32
- data/lib/squib/args/dir_validator.rb +16 -16
- data/lib/squib/args/draw.rb +92 -92
- data/lib/squib/args/embed_adjust.rb +25 -25
- data/lib/squib/args/embed_key.rb +17 -17
- data/lib/squib/args/hand_special.rb +37 -37
- data/lib/squib/args/import.rb +39 -39
- data/lib/squib/args/input_file.rb +37 -37
- data/lib/squib/args/paint.rb +43 -43
- data/lib/squib/args/paragraph.rb +116 -115
- data/lib/squib/args/save_batch.rb +63 -60
- data/lib/squib/args/scale_box.rb +53 -53
- data/lib/squib/args/sheet.rb +72 -72
- data/lib/squib/args/showcase_special.rb +38 -38
- data/lib/squib/args/svg_special.rb +37 -37
- data/lib/squib/args/transform.rb +60 -24
- data/lib/squib/args/typographer.rb +117 -117
- data/lib/squib/card.rb +66 -67
- data/lib/squib/conf.rb +131 -117
- data/lib/squib/constants.rb +12 -178
- data/lib/squib/deck.rb +113 -113
- data/lib/squib/graphics/cairo_context_wrapper.rb +113 -99
- data/lib/squib/graphics/gradient_regex.rb +46 -46
- data/lib/squib/graphics/hand.rb +42 -42
- data/lib/squib/graphics/image.rb +103 -76
- data/lib/squib/graphics/save_doc.rb +103 -103
- data/lib/squib/graphics/save_images.rb +39 -33
- data/lib/squib/graphics/shapes.rb +135 -119
- data/lib/squib/graphics/showcase.rb +85 -85
- data/lib/squib/graphics/text.rb +176 -176
- data/lib/squib/layout_parser.rb +91 -91
- data/lib/squib/layouts/economy.yml +85 -85
- data/lib/squib/layouts/fantasy.yml +101 -101
- data/lib/squib/layouts/hand.yml +62 -62
- data/lib/squib/layouts/playing-card.yml +35 -35
- data/lib/squib/layouts/tuck_box.yml +45 -45
- data/lib/squib/project_template/IDEAS.md +22 -0
- data/lib/squib/project_template/PLAYTESTING.md +26 -0
- data/lib/squib/project_template/RULES.md +21 -0
- data/lib/squib/project_template/config.yml +49 -45
- data/lib/squib/sample_helpers.rb +34 -0
- data/lib/squib/version.rb +10 -10
- data/samples/autoscale_font/_autoscale_font.rb +29 -0
- data/samples/color_shortcuts.rb +6 -6
- data/samples/csv_import.rb +26 -26
- data/samples/custom-config.yml +5 -5
- data/samples/custom_config.rb +18 -18
- data/samples/draw_shapes.rb +48 -45
- data/samples/embed_text.rb +88 -88
- data/samples/excel.rb +55 -55
- data/samples/hand.rb +24 -24
- data/samples/images/_images.rb +104 -0
- data/samples/intro/01_hello.rb +9 -0
- data/samples/intro/02_options.rb +15 -0
- data/samples/intro/03_layout.rb +12 -0
- data/samples/intro/04_arrays.rb +16 -0
- data/samples/intro/05_excel.rb +15 -0
- data/samples/layouts.rb +62 -62
- data/samples/layouts_builtin.rb +51 -51
- data/samples/load_images.rb +99 -78
- data/samples/load_images_config.yml +1 -0
- data/samples/quantity_explosion.csv +2 -2
- data/samples/ranges.rb +64 -64
- data/samples/sample.csv +2 -2
- data/samples/saves.rb +9 -1
- data/samples/sprites.png +0 -0
- data/samples/text/_text.rb +46 -0
- data/samples/text_options.rb +102 -102
- data/spec/api/api_data_spec.rb +117 -117
- data/spec/api/api_settings_spec.rb +37 -37
- data/spec/args/box_spec.rb +127 -127
- data/spec/args/draw_spec.rb +101 -95
- data/spec/args/embed_key_spec.rb +13 -13
- data/spec/args/input_file_spec.rb +21 -21
- data/spec/args/paint_spec.rb +21 -21
- data/spec/args/paragraph_spec.rb +152 -152
- data/spec/args/range_spec.rb +40 -40
- data/spec/args/save_batch_spec.rb +51 -51
- data/spec/args/scale_box_spec.rb +71 -71
- data/spec/args/sheet_spec.rb +58 -58
- data/spec/args/showcase_special_spec.rb +15 -15
- data/spec/args/transform_spec.rb +25 -0
- data/spec/card_spec.rb +11 -0
- data/spec/conf_spec.rb +13 -3
- data/spec/data/conf/unrecognized.yml +4 -0
- data/spec/data/csv/qty.csv +2 -2
- data/spec/data/csv/qty_named.csv +2 -2
- data/spec/data/csv/with_spaces.csv +2 -2
- data/spec/data/samples/autoscale_font.rb.txt +84 -84
- data/spec/data/samples/basic.rb.txt +227 -209
- data/spec/data/samples/config_text_markup.rb.txt +72 -72
- data/spec/data/samples/csv_import.rb.txt +213 -213
- data/spec/data/samples/custom_config.rb.txt +57 -48
- data/spec/data/samples/draw_shapes.rb.txt +555 -3
- data/spec/data/samples/embed_text.rb.txt +283 -283
- data/spec/data/samples/excel.rb.txt +661 -661
- data/spec/data/samples/gradients.rb.txt +77 -79
- data/spec/data/samples/hand.rb.txt +538 -538
- data/spec/data/samples/hello_world.rb.txt +36 -36
- data/spec/data/samples/load_images.rb.txt +170 -0
- data/spec/data/samples/portrait-landscape.rb.txt +51 -49
- data/spec/data/samples/ranges.rb.txt +472 -460
- data/spec/data/samples/saves.rb.txt +810 -801
- data/spec/data/samples/showcase.rb.txt +5926 -5910
- data/spec/data/samples/text_options.rb.txt +1125 -1125
- data/spec/data/samples/tgc_proofs.rb.txt +95 -81
- data/spec/graphics/cairo_context_wrapper_spec.rb +104 -84
- data/spec/graphics/graphics_save_doc_spec.rb +67 -67
- data/spec/samples/diff-with-css.example.html +39 -0
- data/spec/samples/expected/load_images_00.png +0 -0
- data/spec/samples/expected/shape_00.png +0 -0
- data/spec/samples/run_samples_spec.rb +17 -0
- data/spec/samples/samples_regression_spec.rb +72 -82
- data/spec/spec_helper.rb +9 -1
- data/squib.gemspec +49 -48
- data/squib.sublime-project +42 -42
- metadata +94 -48
- data/spec/graphics/graphics_images_spec.rb +0 -94
data/RELEASE TODO.md
CHANGED
@@ -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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
#
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
RSpec::Core::RakeTask.new(:
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
task
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
data/appveyor.yml
ADDED
@@ -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
|
data/lib/squib.rb
CHANGED
@@ -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
|
data/lib/squib/api/background.rb
CHANGED
@@ -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
|
data/lib/squib/api/data.rb
CHANGED
@@ -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
|