spout 0.8.0.beta10 → 0.8.0.beta11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 85db9e44c8437edc8bf46ba106ec1030ce1adf06
4
- data.tar.gz: 453e7af390a7cd5ec6fff0a0ca79bd10cb97e93e
3
+ metadata.gz: d24bb02bdd280c06d7525c64dcf7ba2e8d41cbdd
4
+ data.tar.gz: 4320a06b3bf72ef336bfd211e4b54c2cfbcc379d
5
5
  SHA512:
6
- metadata.gz: 65fb80564f823a0539222ac7080ee782c88dd7859854f2c6f96d0413335a5fe1ffe1cdc04f43491431593728e8928db8a0c9b5b2bce947ef65043576719ec96e
7
- data.tar.gz: b657059a6c7536a1e4166782c08100c564a5c79b6cef99afcc4bfe33211222a17ad2ab9ed65ea0fc63c8e9eef85de5a25d77bb7d7f0e4bb2548871824997ff63
6
+ metadata.gz: b6d305cc70fb6bcbd16e97c7450f0bed6f35bf456f93becc7ce23c97b766d5eda07a06c152941d3c127a61cd8042737013b99c01ba13563226a6bd3186453351
7
+ data.tar.gz: 2493538c40d38fb5708795f4c4b7dc75b0eb3ecf7ec119e0365244a38dae4f86753e60c5f6422bc1361e1e4b8319e8e61dcfcdbe65710745473043d885a8fb9e
data/CHANGELOG.md CHANGED
@@ -14,6 +14,9 @@
14
14
  - Updated to colorize 0.7.2
15
15
  - Use of Ruby 2.1.2 is now recommended
16
16
 
17
+ ### Testing
18
+ - Refactored Spout code and updated test coverage for all major spout commands
19
+
17
20
  ## 0.7.0 (April 16, 2014)
18
21
 
19
22
  ### Enhancements
data/README.md CHANGED
@@ -37,6 +37,7 @@ spout import data_dictionary.csv
37
37
  The CSV should contain at minimal the two column headers:
38
38
 
39
39
  `id`: This column will give the variable its name, and also be used to name the file, i.e. `<id>.json`
40
+
40
41
  `folder`: This can be blank, however it is used to place variables into a folder hiearchy. The folder column can contain forward slashes `/` to place a variable into a subfolder. An example may be, `id`: `myvarid`, `folder`: `Demographics/Subfolder` would create a file `variables/Demographics/Subfolder/myvarid.json`
41
42
 
42
43
  Other columns that will be interpreted include:
@@ -70,18 +71,21 @@ All other columns get grouped into a hash labeled `other`.
70
71
  #### Importing domains from an existing CSV file
71
72
 
72
73
  ```
73
- spout import_domains data_dictionary_domains.csv
74
+ spout import data_dictionary_domains.csv --domains
74
75
  ```
75
76
 
76
77
  The CSV should contain at minimal three column headers:
77
78
 
78
79
  `domain_id`: The name of the associated domain for the choice/option.
80
+
79
81
  `value`: The value of the choice/option.
82
+
80
83
  `display_name`: The display name of the choice/option.
81
84
 
82
85
  Other columns that are imported include:
83
86
 
84
87
  `description`: A longer description of the choice/option.
88
+
85
89
  `folder`: The name of the folder path where the domain resides.
86
90
 
87
91
 
@@ -203,9 +207,12 @@ Example `.spout.yml` file:
203
207
  ```yml
204
208
  visit: visitnumber
205
209
  charts:
206
- - age
207
- - gender
208
- - race
210
+ - chart: age
211
+ title: Age
212
+ - chart: gender
213
+ title: Gender
214
+ - chart: race
215
+ title: Race
209
216
  ```
210
217
 
211
218
  To only generate graphs for a few select variables, add the variable names after the `spout graphs` command.
data/bin/spout CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  require File.expand_path('../../lib/spout', __FILE__)
4
4
 
5
- Spout::Actions.new.interpret(ARGV)
5
+ Spout.launch(ARGV)
data/lib/spout/actions.rb CHANGED
@@ -1,172 +1,92 @@
1
- module Spout
2
- class Actions
3
-
4
- def interpret(argv)
5
- case argv.first
6
- when 'new', 'n', 'ne', '-new', '-n', '-ne'
7
- new_template_dictionary(argv)
8
- when '--version', '-v', '-ve', '-ver', 'version', 'v', 've', 'ver'
9
- puts "Spout #{Spout::VERSION::STRING}"
10
- when 'test', 't', 'te', 'tes', '--test', '-t', '-te', '-tes'
11
- system "bundle exec rake HIDE_PASSING_TESTS=true"
12
- when 'tv'
13
- system "bundle exec rake"
14
- when 'import', 'i', 'im', 'imp', '--import', '-i', '-im', '-imp'
15
- import_from_csv(argv)
16
- when 'import_domain', '--import_domain', 'import_domains', '--import_domains'
17
- import_from_csv(argv, 'domains')
18
- when 'export', 'e', 'ex', 'exp', '--export', '-e', '-ex', '-exp'
19
- new_data_dictionary_export(argv)
20
- when 'coverage', '-coverage', '--coverage', 'c', '-c'
21
- coverage_report(argv)
22
- when 'pngs', '-pngs', '--pngs', 'p', '-p'
23
- generate_images(argv.last(argv.size - 1))
24
- when 'graphs', '-graphs', '--graphs', 'g', '-g'
25
- generate_charts_and_tables(argv.last(argv.size - 1))
26
- when 'outliers', '-outliers', '--outliers', 'o', '-o'
27
- outliers_report(argv)
28
- else
29
- help
30
- end
31
- end
32
-
33
- protected
34
-
35
- def csv_usage
36
- usage = <<-EOT
37
-
38
- Usage: spout import CSVFILE
39
-
40
- The CSVFILE must be the location of a valid CSV file.
41
-
42
- EOT
43
- usage
44
- end
45
-
46
- def import_from_csv(argv, type = "")
47
- csv_file = File.join(argv[1].to_s.strip)
48
- if File.exists?(csv_file)
49
- system "bundle exec rake spout:import CSV=#{csv_file} #{'TYPE='+type if type.to_s != ''}"
50
- else
51
- puts csv_usage
52
- end
53
- end
54
-
55
- def help
56
- help_message = <<-EOT
57
-
58
- Usage: spout COMMAND [ARGS]
59
-
60
- The most common spout commands are:
61
- [n]ew Create a new Spout dictionary.
62
- `spout new <project_name>` creates a new
63
- data dictionary in `./<project_name>`
64
- [t]est Run tests and show failing tests
65
- [tv] Run the tests and show passing and failing
66
- tests
67
- [i]mport Import a CSV file into the JSON dictionary
68
- [e]xport [1.0.0] Export the JSON dictionary to CSV format
69
- [c]overage Coverage report, requires dataset CSVs
70
- in `<project_name>/csvs/<version>`
71
- [o]utliers Outlier report, requires dataset CSVs
72
- in `<project_name>/csvs/<version>`
73
- [p]ngs Generates images for each variable in a
74
- dataset and places them
75
- in `<project_name>/images/<version>/`
76
- [g]raphs Generates JSON graphs for each variable
77
- in a dataset and places them
78
- in `<project_name>/graphs/<version>/`
79
- [v]ersion Returns the version of Spout
80
-
81
- Commands can be referenced by the first letter:
82
- Ex: `spout t`, for test
83
-
84
- EOT
85
- puts help_message
86
- end
87
-
88
- def new_data_dictionary_export(argv)
89
- version = argv[1].to_s.gsub(/[^a-zA-Z0-9\.-]/, '_').strip
90
- version_string = (version == '' ? "" : "VERSION=#{version}")
91
- system "bundle exec rake spout:create #{version_string}"
92
- end
93
-
94
- def new_template_dictionary(argv)
95
- @full_path = File.join(argv[1].to_s.strip)
96
- usage = <<-EOT
97
-
98
- Usage: spout new FOLDER
99
-
100
- The FOLDER must be empty or new.
101
-
102
- EOT
103
-
104
- if @full_path == '' or ( Dir.exists?(@full_path) and (Dir.entries(@full_path) & ['.gitignore', '.ruby-version', '.travis.yml', 'Gemfile', 'Rakefile', 'domains', 'variables', 'test']).size > 0 )
105
- puts usage
106
- exit(0)
107
- end
108
-
109
- FileUtils.mkpath(@full_path)
110
-
111
- copy_file 'gitignore', '.gitignore'
112
- copy_file 'ruby-version', '.ruby-version'
113
- copy_file 'travis.yml', '.travis.yml'
114
- copy_file 'Gemfile'
115
- copy_file 'Rakefile'
116
- directory 'domains'
117
- copy_file 'keep', 'domains/.keep'
118
- directory 'variables'
119
- copy_file 'keep', 'variables/.keep'
120
- directory 'test'
121
- copy_file 'test/dictionary_test.rb'
122
- copy_file 'test/test_helper.rb'
123
- puts " run".colorize( :green ) + " bundle install".colorize( :light_cyan )
124
- Dir.chdir(@full_path)
125
- system "bundle install"
126
- end
127
-
128
- def coverage_report(argv)
129
- system "bundle exec rake spout:coverage"
130
- end
131
-
132
- def outliers_report(argv)
133
- system "bundle exec rake spout:outliers"
134
- end
135
-
136
- def flag_values(flags, param)
137
- flags.select{|f| f[0..((param.size + 3) - 1)] == "--#{param}-" and f.length > param.size + 3}.collect{|f| f[(param.size + 3)..-1]}
138
- end
139
-
140
- def generate_images(flags)
141
- params = {}
142
- params['types'] = flag_values(flags, 'type')
143
- params['variable_ids'] = flag_values(flags, 'id')
144
- params['sizes'] = flag_values(flags, 'size')
145
-
146
- params_string = params.collect{|key, values| "#{key}=#{values.join(',')}"}.join(' ')
147
-
148
- system "bundle exec rake spout:images #{params_string}"
149
- end
150
-
151
- def generate_charts_and_tables(variables)
152
- system "bundle exec rake spout:json variables=#{variables.join(',')}"
153
- end
154
-
155
- private
156
-
157
- def copy_file(template_file, file_name = '')
158
- file_name = template_file if file_name == ''
159
- file_path = File.join(@full_path, file_name)
160
- template_file_path = File.join(File.expand_path(File.dirname(__FILE__)), "templates", template_file)
161
- puts " create".colorize( :green ) + " #{file_name}"
162
- FileUtils.copy(template_file_path, file_path)
163
- end
164
-
165
- def directory(directory_name)
166
- directory_path = File.join(@full_path, directory_name)
167
- puts " create".colorize( :green ) + " #{directory_name}"
168
- FileUtils.mkpath(directory_path)
169
- end
170
-
171
- end
172
- end
1
+ # module Spout
2
+ # class Actions
3
+
4
+ # def interpret(argv)
5
+ # # case argv.first.to_s.scan(/\w/).first
6
+ # case argv.first
7
+ # when 'new', 'n', 'ne', '-new', '-n', '-ne'
8
+ # new_template_dictionary(argv)
9
+ # when '--version', '-v', '-ve', '-ver', 'version', 'v', 've', 'ver'
10
+ # puts "Spout #{Spout::VERSION::STRING}"
11
+ # when 'test', 't', 'te', 'tes', '--test', '-t', '-te', '-tes'
12
+ # system "bundle exec rake HIDE_PASSING_TESTS=true"
13
+ # # when 'tv'
14
+ # # system "bundle exec rake"
15
+ # when 'import', 'i', 'im', 'imp', '--import', '-i', '-im', '-imp'
16
+ # import_from_csv(argv)
17
+ # when 'import_domain', '--import_domain', 'import_domains', '--import_domains'
18
+ # import_from_csv(argv, 'domains')
19
+ # when 'export', 'e', 'ex', 'exp', '--export', '-e', '-ex', '-exp'
20
+ # new_data_dictionary_export(argv)
21
+ # when 'coverage', '-coverage', '--coverage', 'c', '-c'
22
+ # coverage_report(argv)
23
+ # when 'pngs', '-pngs', '--pngs', 'p', '-p'
24
+ # generate_images(argv.last(argv.size - 1))
25
+ # when 'graphs', '-graphs', '--graphs', 'g', '-g'
26
+ # generate_charts_and_tables(argv.last(argv.size - 1))
27
+ # when 'outliers', '-outliers', '--outliers', 'o', '-o'
28
+ # outliers_report(argv)
29
+ # # else
30
+ # # help
31
+ # end
32
+ # end
33
+
34
+ # protected
35
+
36
+ # def csv_usage
37
+ # usage = <<-EOT
38
+
39
+ # Usage: spout import CSVFILE
40
+
41
+ # The CSVFILE must be the location of a valid CSV file.
42
+
43
+ # EOT
44
+ # usage
45
+ # end
46
+
47
+ # def import_from_csv(argv, type = "")
48
+ # csv_file = File.join(argv[1].to_s.strip)
49
+ # if File.exists?(csv_file)
50
+ # system "bundle exec rake spout:import CSV=#{csv_file} #{'TYPE='+type if type.to_s != ''}"
51
+ # else
52
+ # puts csv_usage
53
+ # end
54
+ # end
55
+
56
+ # def new_data_dictionary_export(argv)
57
+ # version = argv[1].to_s.gsub(/[^a-zA-Z0-9\.-]/, '_').strip
58
+ # version_string = (version == '' ? "" : "VERSION=#{version}")
59
+ # system "bundle exec rake spout:create #{version_string}"
60
+ # end
61
+
62
+ # def coverage_report(argv)
63
+ # require 'spout/commands/coverage'
64
+ # Spout::Commands::Coverage.new(standard_version, argv)
65
+ # # system "bundle exec rake spout:coverage"
66
+ # end
67
+
68
+ # def outliers_report(argv)
69
+ # system "bundle exec rake spout:outliers"
70
+ # end
71
+
72
+ # def flag_values(flags, param)
73
+ # flags.select{|f| f[0..((param.size + 3) - 1)] == "--#{param}-" and f.length > param.size + 3}.collect{|f| f[(param.size + 3)..-1]}
74
+ # end
75
+
76
+ # def generate_images(flags)
77
+ # params = {}
78
+ # params['types'] = flag_values(flags, 'type')
79
+ # params['variable_ids'] = flag_values(flags, 'id')
80
+ # params['sizes'] = flag_values(flags, 'size')
81
+
82
+ # params_string = params.collect{|key, values| "#{key}=#{values.join(',')}"}.join(' ')
83
+
84
+ # system "bundle exec rake spout:images #{params_string}"
85
+ # end
86
+
87
+ # def generate_charts_and_tables(variables)
88
+ # system "bundle exec rake spout:json variables=#{variables.join(',')}"
89
+ # end
90
+
91
+ # end
92
+ # end
@@ -1,13 +1,18 @@
1
1
  require 'yaml'
2
+ require 'erb'
2
3
 
3
4
  require 'spout/helpers/subject_loader'
4
5
  require 'spout/models/coverage_result'
6
+ require 'spout/helpers/number_helper'
5
7
 
6
8
  module Spout
7
9
  module Commands
8
10
  class Coverage
9
- def initialize(standard_version)
11
+ include Spout::Helpers::NumberHelper
12
+
13
+ def initialize(standard_version, argv)
10
14
  @standard_version = standard_version
15
+ @console = (argv.delete('--console') != nil)
11
16
 
12
17
  @variable_files = Dir.glob("variables/**/*.json")
13
18
  @valid_ids = []
@@ -60,10 +65,12 @@ module Spout
60
65
  file.puts ERB.new(File.read(erb_location)).result(binding)
61
66
  end
62
67
 
63
- open_command = 'open' if RUBY_PLATFORM.match(/darwin/) != nil
64
- open_command = 'start' if RUBY_PLATFORM.match(/mingw/) != nil
68
+ unless @console
69
+ open_command = 'open' if RUBY_PLATFORM.match(/darwin/) != nil
70
+ open_command = 'start' if RUBY_PLATFORM.match(/mingw/) != nil
65
71
 
66
- system "#{open_command} #{coverage_file}" if ['start', 'open'].include?(open_command)
72
+ system "#{open_command} #{coverage_file}" if ['start', 'open'].include?(open_command)
73
+ end
67
74
  puts "#{coverage_file}\n\n"
68
75
  end
69
76
  end
@@ -0,0 +1,62 @@
1
+ require 'csv'
2
+
3
+ module Spout
4
+ module Commands
5
+ class Exporter
6
+ def initialize(standard_version, argv)
7
+ @csv_file = argv[1].to_s
8
+ @standard_version = standard_version
9
+ expanded_export!
10
+ end
11
+
12
+ private
13
+
14
+ def expanded_export!
15
+ folder = "dd/#{@standard_version}"
16
+ puts " create".colorize( :green ) + " #{folder}"
17
+ FileUtils.mkpath folder
18
+
19
+ variables_export_file = "variables.csv"
20
+ puts " export".colorize( :blue ) + " #{folder}/#{variables_export_file}"
21
+ CSV.open("#{folder}/#{variables_export_file}", "wb") do |csv|
22
+ keys = %w(id display_name description type units domain labels calculation)
23
+ csv << ['folder'] + keys
24
+ Dir.glob("variables/**/*.json").each do |file|
25
+ if json = JSON.parse(File.read(file)) rescue false
26
+ variable_folder = variable_folder_path(file)
27
+ csv << [variable_folder] + keys.collect{|key| json[key].kind_of?(Array) ? json[key].join(';') : json[key].to_s}
28
+ end
29
+ end
30
+ end
31
+ domains_export_file = "domains.csv"
32
+ puts " export".colorize( :blue ) + " #{folder}/#{domains_export_file}"
33
+ CSV.open("#{folder}/#{domains_export_file}", "wb") do |csv|
34
+ keys = %w(value display_name description)
35
+ csv << ['folder', 'domain_id'] + keys
36
+ Dir.glob("domains/**/*.json").each do |file|
37
+ if json = JSON.parse(File.read(file)) rescue false
38
+ domain_folder = domain_folder_path(file)
39
+ domain_name = extract_domain_name(file)
40
+ json.each do |hash|
41
+ csv << [domain_folder, domain_name] + keys.collect{|key| hash[key]}
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def extract_domain_name(file)
49
+ file.gsub(/domains\//, '').split('/').last.to_s.gsub(/.json/, '')
50
+ end
51
+
52
+ def domain_folder_path(file)
53
+ file.gsub(/domains\//, '').split('/')[0..-2].join('/')
54
+ end
55
+
56
+ def variable_folder_path(file)
57
+ file.gsub(/variables\//, '').split('/')[0..-2].join('/')
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -28,7 +28,7 @@ module Spout
28
28
  else
29
29
  puts "The YAML file needs to be in the following format:"
30
30
  puts "---\nvisit: visit_variable_name\ncharts:\n- chart: age_variable_name\n title: Age\n- chart: gender_variable_name\n title: Gender\n- chart: race_variable_name\n title: Race\n"
31
- exit
31
+ return self
32
32
  end
33
33
 
34
34
  if Spout::Helpers::ChartTypes::get_json(@visit, 'variable') == nil
@@ -37,12 +37,12 @@ module Spout
37
37
  else
38
38
  puts "Could not find the following visit variable: #{@visit}"
39
39
  end
40
- exit
40
+ return self
41
41
  end
42
42
  missing_variables = chart_variables.select{|c| Spout::Helpers::ChartTypes::get_json(c['chart'], 'variable') == nil}
43
43
  if missing_variables.count > 0
44
44
  puts "Could not find the following chart variable#{'s' unless missing_variables.size == 1}: #{missing_variables.join(', ')}"
45
- exit
45
+ return self
46
46
  end
47
47
 
48
48
  argv_string = variables.join(',')
@@ -11,9 +11,11 @@ module Spout
11
11
  module Commands
12
12
  class Images
13
13
 
14
- def initialize(types, variable_ids, sizes, standard_version)
14
+ def initialize(types, variable_ids, sizes, standard_version, argv)
15
15
  @variable_files = Dir.glob('variables/**/*.json')
16
16
  @standard_version = standard_version
17
+ @pretend = (argv.delete('--pretend') != nil)
18
+
17
19
 
18
20
  @valid_ids = variable_ids
19
21
 
@@ -60,42 +62,44 @@ module Spout
60
62
 
61
63
  filtered_subjects = @subjects.select{ |s| s.send(@visit) != nil }
62
64
 
63
- File.open(tmp_options_file, "w") do |outfile|
64
- chart_json = Spout::Helpers::ChartTypes::chart_histogram(@visit, filtered_subjects, json, variable_name)
65
- outfile.puts <<-eos
66
- {
67
- "credits": {
68
- "enabled": false
69
- },
70
- "chart": {
71
- "type": "column"
72
- },
73
- "title": {
74
- "text": ""
75
- },
76
- "xAxis": {
77
- "categories": #{chart_json[:categories].to_json}
78
- },
79
- "yAxis": {
65
+ chart_json = Spout::Helpers::ChartTypes::chart_histogram(@visit, filtered_subjects, json, variable_name)
66
+
67
+ if chart_json
68
+ File.open(tmp_options_file, "w") do |outfile|
69
+ outfile.puts <<-eos
70
+ {
71
+ "credits": {
72
+ "enabled": false
73
+ },
74
+ "chart": {
75
+ "type": "column"
76
+ },
80
77
  "title": {
81
- "text": #{chart_json[:units].to_json}
82
- }
83
- },
84
- "plotOptions": {
85
- "column": {
86
- "pointPadding": 0.2,
87
- "borderWidth": 0,
88
- "stacking": #{chart_json[:stacking].to_json}
89
- }
90
- },
91
- "series": #{chart_json[:series].to_json}
92
- }
93
- eos
78
+ "text": ""
79
+ },
80
+ "xAxis": {
81
+ "categories": #{chart_json[:categories].to_json}
82
+ },
83
+ "yAxis": {
84
+ "title": {
85
+ "text": #{chart_json[:units].to_json}
86
+ }
87
+ },
88
+ "plotOptions": {
89
+ "column": {
90
+ "pointPadding": 0.2,
91
+ "borderWidth": 0,
92
+ "stacking": #{chart_json[:stacking].to_json}
93
+ }
94
+ },
95
+ "series": #{chart_json[:series].to_json}
96
+ }
97
+ eos
98
+ end
99
+ run_phantom_js("#{json['id']}-lg.png", 600, tmp_options_file) if sizes.size == 0 or sizes.include?('lg')
100
+ run_phantom_js("#{json['id']}.png", 75, tmp_options_file) if sizes.size == 0 or sizes.include?('sm')
94
101
  end
95
102
 
96
-
97
- run_phantom_js("#{json['id']}-lg.png", 600, tmp_options_file) if sizes.size == 0 or sizes.include?('lg')
98
- run_phantom_js("#{json['id']}.png", 75, tmp_options_file) if sizes.size == 0 or sizes.include?('sm')
99
103
  end
100
104
  File.delete(tmp_options_file) if File.exists?(tmp_options_file)
101
105
  end
@@ -267,8 +271,13 @@ module Spout
267
271
  end
268
272
 
269
273
  phantomjs_command = "#{open_command} #{directory}/highcharts-convert.js -infile #{tmp_options_file} -outfile #{graph_path} -scale 2.5 -width #{width} -constr Chart"
270
- # puts phantomjs_command
271
- `#{phantomjs_command}`
274
+
275
+ if @pretend
276
+ puts phantomjs_command
277
+ else
278
+ `#{phantomjs_command}`
279
+ end
280
+
272
281
  end
273
282
 
274
283
  end
@@ -0,0 +1,125 @@
1
+ require 'csv'
2
+
3
+ module Spout
4
+ module Commands
5
+ class Importer
6
+ def initialize(argv)
7
+ use_domains = (argv.delete('--domains') != nil)
8
+
9
+ @csv_file = argv[1].to_s
10
+
11
+ unless File.exists?(@csv_file)
12
+ puts csv_usage
13
+ return self
14
+ end
15
+
16
+ if use_domains
17
+ import_domains
18
+ else
19
+ import_variables
20
+ end
21
+
22
+ end
23
+
24
+ def csv_usage
25
+ usage = <<-EOT
26
+
27
+ Usage: spout import CSVFILE
28
+
29
+ The CSVFILE must be the location of a valid CSV file.
30
+
31
+ EOT
32
+ usage
33
+ end
34
+
35
+ def import_variables
36
+ CSV.parse( File.open(@csv_file, 'r:iso-8859-1:utf-8'){|f| f.read}, headers: true ) do |line|
37
+ row = line.to_hash
38
+ if not row.keys.include?('id')
39
+ puts "\nMissing column header `".colorize( :red ) + "id".colorize( :light_cyan ) + "` in data dictionary.".colorize( :red ) + additional_csv_info
40
+ exit(1)
41
+ end
42
+ next if row['id'] == ''
43
+ folder = File.join('variables', row.delete('folder').to_s)
44
+ FileUtils.mkpath folder
45
+ hash = {}
46
+ id = row.delete('id')
47
+ hash['id'] = id
48
+ hash['display_name'] = row.delete('display_name')
49
+ hash['description'] = row.delete('description').to_s
50
+ hash['type'] = row.delete('type')
51
+ domain = row.delete('domain').to_s
52
+ hash['domain'] = domain if domain != ''
53
+ units = row.delete('units').to_s
54
+ hash['units'] = units if units != ''
55
+ calculation = row.delete('calculation').to_s
56
+ hash['calculation'] = calculation if calculation != ''
57
+ labels = row.delete('labels').to_s.split(';')
58
+ hash['labels'] = labels if labels.size > 0
59
+ hash['other'] = row unless row.empty?
60
+
61
+ file_name = File.join(folder, id.to_s.downcase + '.json')
62
+ File.open(file_name, 'w') do |file|
63
+ file.write(JSON.pretty_generate(hash) + "\n")
64
+ end
65
+ puts " create".colorize( :green ) + " #{file_name}"
66
+ end
67
+ end
68
+
69
+ def import_domains
70
+ domains = {}
71
+
72
+ CSV.parse( File.open(@csv_file, 'r:iso-8859-1:utf-8'){|f| f.read}, headers: true ) do |line|
73
+ row = line.to_hash
74
+ if not row.keys.include?('domain_id')
75
+ puts "\nMissing column header `".colorize( :red ) + "domain_id".colorize( :light_cyan ) + "` in data dictionary.".colorize( :red ) + additional_csv_info
76
+ exit(1)
77
+ end
78
+ if not row.keys.include?('value')
79
+ puts "\nMissing column header `".colorize( :red ) + "value".colorize( :light_cyan ) + "` in data dictionary.".colorize( :red ) + additional_csv_info
80
+ exit(1)
81
+ end
82
+ if not row.keys.include?('display_name')
83
+ puts "\nMissing column header `".colorize( :red ) + "display_name".colorize( :light_cyan ) + "` in data dictionary.".colorize( :red ) + additional_csv_info
84
+ exit(1)
85
+ end
86
+
87
+ next if row['domain_id'].to_s == '' or row['value'].to_s == '' or row['display_name'].to_s == ''
88
+ folder = File.join('domains', row['folder'].to_s).gsub(/[^a-zA-Z0-9_\/\.-]/, '_')
89
+ domain_name = row['domain_id'].to_s.gsub(/[^a-zA-Z0-9_\/\.-]/, '_')
90
+ domains[domain_name] ||= {}
91
+ domains[domain_name]["folder"] = folder
92
+ domains[domain_name]["options"] ||= []
93
+
94
+ hash = {}
95
+ hash['value'] = row.delete('value').to_s
96
+ hash['display_name'] = row.delete('display_name').to_s
97
+ hash['description'] = row.delete('description').to_s
98
+
99
+ domains[domain_name]["options"] << hash
100
+ end
101
+
102
+ domains.each do |domain_name, domain_hash|
103
+ folder = domain_hash["folder"]
104
+ FileUtils.mkpath folder
105
+
106
+ file_name = File.join(folder, domain_name.to_s.downcase + '.json')
107
+
108
+ File.open(file_name, 'w') do |file|
109
+ file.write(JSON.pretty_generate(domain_hash["options"]) + "\n")
110
+ end
111
+ puts " create".colorize( :green ) + " #{file_name}"
112
+ end
113
+
114
+ end
115
+
116
+ private
117
+
118
+ def additional_csv_info
119
+ "\n\nFor additional information on specifying CSV column headers before import see:\n\n " + "https://github.com/sleepepi/spout#generate-a-new-repository-from-an-existing-csv-file".colorize( :light_cyan ) + "\n\n"
120
+ end
121
+
122
+
123
+ end
124
+ end
125
+ end
@@ -1,13 +1,18 @@
1
1
  require 'yaml'
2
+ require 'erb'
2
3
 
3
4
  require 'spout/helpers/subject_loader'
4
5
  require 'spout/models/outlier_result'
6
+ require 'spout/helpers/number_helper'
5
7
 
6
8
  module Spout
7
9
  module Commands
8
10
  class Outliers
9
- def initialize(standard_version)
11
+ include Spout::Helpers::NumberHelper
12
+
13
+ def initialize(standard_version, argv)
10
14
  @standard_version = standard_version
15
+ @console = (argv.delete('--console') != nil)
11
16
 
12
17
  @variable_files = Dir.glob('variables/**/*.json')
13
18
  @valid_ids = []
@@ -19,6 +24,7 @@ module Spout
19
24
  @subject_loader = Spout::Helpers::SubjectLoader.new(@variable_files, @valid_ids, @standard_version, @number_of_rows, @visit)
20
25
  @subject_loader.load_subjects_from_csvs!
21
26
  @subjects = @subject_loader.subjects
27
+ run_outliers_report!
22
28
  end
23
29
 
24
30
  def run_outliers_report!
@@ -47,13 +53,15 @@ module Spout
47
53
  file.puts ERB.new(File.read(erb_location)).result(binding)
48
54
  end
49
55
 
50
- open_command = 'open' if RUBY_PLATFORM.match(/darwin/) != nil
51
- open_command = 'start' if RUBY_PLATFORM.match(/mingw/) != nil
56
+ unless @console
57
+ open_command = 'open' if RUBY_PLATFORM.match(/darwin/) != nil
58
+ open_command = 'start' if RUBY_PLATFORM.match(/mingw/) != nil
52
59
 
53
- system "#{open_command} #{html_file}" if ['start', 'open'].include?(open_command)
60
+ system "#{open_command} #{html_file}" if ['start', 'open'].include?(open_command)
61
+ end
54
62
  puts "#{html_file}\n\n"
63
+ return self
55
64
  end
56
-
57
65
  end
58
66
  end
59
67
  end
@@ -0,0 +1,66 @@
1
+ TEMPLATES_DIRECTORY = File.expand_path('../../templates', __FILE__)
2
+
3
+ module Spout
4
+ module Commands
5
+ class ProjectGenerator
6
+ def initialize(argv)
7
+ generate_folder_structure!(argv)
8
+ end
9
+
10
+ def generate_folder_structure!(argv)
11
+ skip_gemfile = (argv.delete('--skip-gemfile') != nil)
12
+ @full_path = File.join(argv[1].to_s.strip)
13
+ usage = <<-EOT
14
+
15
+ Usage: spout new FOLDER
16
+
17
+ The FOLDER must be empty or new.
18
+
19
+ EOT
20
+
21
+ if @full_path == '' or ( Dir.exists?(@full_path) and (Dir.entries(@full_path) & ['.gitignore', '.ruby-version', '.travis.yml', 'Gemfile', 'Rakefile', 'domains', 'variables', 'test']).size > 0 )
22
+ puts usage
23
+ exit(0)
24
+ end
25
+
26
+ FileUtils.mkpath(@full_path)
27
+
28
+ copy_file 'gitignore', '.gitignore'
29
+ copy_file 'ruby-version', '.ruby-version'
30
+ copy_file 'travis.yml', '.travis.yml'
31
+ copy_file 'spout.yml', '.spout.yml'
32
+ copy_file 'Gemfile'
33
+ copy_file 'Rakefile'
34
+ directory 'domains'
35
+ copy_file 'keep', 'domains/.keep'
36
+ directory 'variables'
37
+ copy_file 'keep', 'variables/.keep'
38
+ directory 'test'
39
+ copy_file 'test/dictionary_test.rb'
40
+ copy_file 'test/test_helper.rb'
41
+ unless skip_gemfile
42
+ puts " run".colorize( :green ) + " bundle install".colorize( :light_cyan )
43
+ Dir.chdir(@full_path)
44
+ system "bundle install"
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def copy_file(template_file, file_name = '')
51
+ file_name = template_file if file_name == ''
52
+ file_path = File.join(@full_path, file_name)
53
+ template_file_path = File.join(TEMPLATES_DIRECTORY, template_file)
54
+ puts " create".colorize( :green ) + " #{file_name}"
55
+ FileUtils.copy(template_file_path, file_path)
56
+ end
57
+
58
+ def directory(directory_name)
59
+ directory_path = File.join(@full_path, directory_name)
60
+ puts " create".colorize( :green ) + " #{directory_name}"
61
+ FileUtils.mkpath(directory_path)
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+ module Spout
2
+ module Helpers
3
+ module NumberHelper
4
+ def number_with_delimiter(number, delimiter = ",")
5
+ number.to_s.reverse.scan(/(?:\d*\.)?\d{1,3}-?/).join(',').reverse
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,5 +1,7 @@
1
- require 'spout/models/subject'
1
+ require 'csv'
2
+ require 'json'
2
3
 
4
+ require 'spout/models/subject'
3
5
 
4
6
  module Spout
5
7
  module Helpers
@@ -31,7 +33,6 @@ module Spout
31
33
  count = 0
32
34
  puts "Parsing: #{csv_file}"
33
35
  CSV.parse( File.open(csv_file, 'r:iso-8859-1:utf-8'){|f| f.read}, headers: true, header_converters: lambda { |h| h.to_s.downcase } ) do |line|
34
-
35
36
  row = line.to_hash
36
37
  count += 1
37
38
  puts "Line: #{count}" if (count % 1000 == 0)
@@ -42,10 +43,11 @@ module Spout
42
43
  unless t.respond_to?(key)
43
44
  t.class.send(:define_method, "#{key}") { instance_variable_get("@#{key}") }
44
45
  t.class.send(:define_method, "#{key}=") { |value| instance_variable_set("@#{key}", value) }
45
- all_methods[key] ||= []
46
- all_methods[key] << csv_file
47
46
  end
48
47
 
48
+ @all_methods[key] ||= []
49
+ @all_methods[key] = @all_methods[key] | [csv_file]
50
+
49
51
  unless value == nil
50
52
  t.send("#{key}=", value)
51
53
  end
@@ -9,196 +9,3 @@ Rake::TestTask.new do |t|
9
9
  end
10
10
 
11
11
  task default: :test
12
-
13
- namespace :spout do
14
- require 'csv'
15
- require 'fileutils'
16
- require 'rubygems'
17
- require 'json'
18
- require 'erb'
19
-
20
- desc 'Create Data Dictionary from repository'
21
- task :create do
22
- folder = "dd/#{ENV['VERSION'] || standard_version}"
23
- puts " create".colorize( :green ) + " #{folder}"
24
- FileUtils.mkpath folder
25
-
26
- expanded_export(folder)
27
- end
28
-
29
- desc 'Initialize JSON repository from a CSV file: CSV=datadictionary.csv'
30
- task :import do
31
- puts ENV['CSV'].inspect
32
- if File.exists?(ENV['CSV'].to_s)
33
- ENV['TYPE'] == 'domains' ? import_domains : import_variables
34
- else
35
- puts "\nPlease specify a valid CSV file.".colorize( :red ) + additional_csv_info
36
- end
37
- end
38
-
39
- desc 'Match CSV dataset with JSON repository'
40
- task :coverage do
41
- require 'spout/commands/coverage'
42
- Spout::Commands::Coverage.new(standard_version)
43
- end
44
-
45
- desc 'Identify Outliers in CSV dataset'
46
- task :outliers do
47
- require 'spout/commands/outliers'
48
- outliers = Spout::Commands::Outliers.new(standard_version)
49
- outliers.run_outliers_report!
50
- end
51
-
52
- desc 'Match CSV dataset with JSON repository'
53
- task :images do
54
- require 'spout/commands/images'
55
- types = ENV['types'].to_s.split(',').collect{|t| t.to_s.downcase}
56
- variable_ids = ENV['variable_ids'].to_s.split(',').collect{|vid| vid.to_s.downcase}
57
- sizes = ENV['sizes'].to_s.split(',').collect{|s| s.to_s.downcase}
58
- Spout::Commands::Images.new(types, variable_ids, sizes, standard_version)
59
- end
60
-
61
- desc 'Generate JSON charts and tables'
62
- task :json do
63
- require 'spout/commands/graphs'
64
- variables = ENV['variables'].to_s.split(',').collect{|s| s.to_s.downcase}
65
- Spout::Commands::Graphs.new(variables, standard_version)
66
- end
67
-
68
- end
69
-
70
- def number_with_delimiter(number, delimiter = ",")
71
- number.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
72
- end
73
-
74
- def standard_version
75
- version = File.open('VERSION', &:readline).strip rescue ''
76
- version == '' ? '1.0.0' : version
77
- end
78
-
79
- def expanded_export(folder)
80
- variables_export_file = "variables.csv"
81
- puts " export".colorize( :blue ) + " #{folder}/#{variables_export_file}"
82
- CSV.open("#{folder}/#{variables_export_file}", "wb") do |csv|
83
- keys = %w(id display_name description type units domain labels calculation)
84
- csv << ['folder'] + keys
85
- Dir.glob("variables/**/*.json").each do |file|
86
- if json = JSON.parse(File.read(file)) rescue false
87
- variable_folder = variable_folder_path(file)
88
- csv << [variable_folder] + keys.collect{|key| json[key].kind_of?(Array) ? json[key].join(';') : json[key].to_s}
89
- end
90
- end
91
- end
92
- domains_export_file = "domains.csv"
93
- puts " export".colorize( :blue ) + " #{folder}/#{domains_export_file}"
94
- CSV.open("#{folder}/#{domains_export_file}", "wb") do |csv|
95
- keys = %w(value display_name description)
96
- csv << ['folder', 'domain_id'] + keys
97
- Dir.glob("domains/**/*.json").each do |file|
98
- if json = JSON.parse(File.read(file)) rescue false
99
- domain_folder = domain_folder_path(file)
100
- domain_name = extract_domain_name(file)
101
- json.each do |hash|
102
- csv << [domain_folder, domain_name] + keys.collect{|key| hash[key]}
103
- end
104
- end
105
- end
106
- end
107
- end
108
-
109
- def extract_domain_name(file)
110
- file.gsub(/domains\//, '').split('/').last.to_s.gsub(/.json/, '')
111
- end
112
-
113
- def domain_folder_path(file)
114
- file.gsub(/domains\//, '').split('/')[0..-2].join('/')
115
- end
116
-
117
- def variable_folder_path(file)
118
- file.gsub(/variables\//, '').split('/')[0..-2].join('/')
119
- end
120
-
121
- def import_variables
122
- CSV.parse( File.open(ENV['CSV'].to_s, 'r:iso-8859-1:utf-8'){|f| f.read}, headers: true ) do |line|
123
- row = line.to_hash
124
- if not row.keys.include?('id')
125
- puts "\nMissing column header `".colorize( :red ) + "id".colorize( :light_cyan ) + "` in data dictionary.".colorize( :red ) + additional_csv_info
126
- exit(1)
127
- end
128
- next if row['id'] == ''
129
- folder = File.join('variables', row.delete('folder').to_s)
130
- FileUtils.mkpath folder
131
- hash = {}
132
- id = row.delete('id')
133
- hash['id'] = id
134
- hash['display_name'] = row.delete('display_name')
135
- hash['description'] = row.delete('description').to_s
136
- hash['type'] = row.delete('type')
137
- domain = row.delete('domain').to_s
138
- hash['domain'] = domain if domain != ''
139
- units = row.delete('units').to_s
140
- hash['units'] = units if units != ''
141
- calculation = row.delete('calculation').to_s
142
- hash['calculation'] = calculation if calculation != ''
143
- labels = row.delete('labels').to_s.split(';')
144
- hash['labels'] = labels if labels.size > 0
145
- hash['other'] = row unless row.empty?
146
-
147
- file_name = File.join(folder, id.to_s.downcase + '.json')
148
- File.open(file_name, 'w') do |file|
149
- file.write(JSON.pretty_generate(hash) + "\n")
150
- end
151
- puts " create".colorize( :green ) + " #{file_name}"
152
- end
153
- end
154
-
155
- def import_domains
156
- domains = {}
157
-
158
- CSV.parse( File.open(ENV['CSV'].to_s, 'r:iso-8859-1:utf-8'){|f| f.read}, headers: true ) do |line|
159
- row = line.to_hash
160
- if not row.keys.include?('domain_id')
161
- puts "\nMissing column header `".colorize( :red ) + "domain_id".colorize( :light_cyan ) + "` in data dictionary.".colorize( :red ) + additional_csv_info
162
- exit(1)
163
- end
164
- if not row.keys.include?('value')
165
- puts "\nMissing column header `".colorize( :red ) + "value".colorize( :light_cyan ) + "` in data dictionary.".colorize( :red ) + additional_csv_info
166
- exit(1)
167
- end
168
- if not row.keys.include?('display_name')
169
- puts "\nMissing column header `".colorize( :red ) + "display_name".colorize( :light_cyan ) + "` in data dictionary.".colorize( :red ) + additional_csv_info
170
- exit(1)
171
- end
172
-
173
- next if row['domain_id'].to_s == '' or row['value'].to_s == '' or row['display_name'].to_s == ''
174
- folder = File.join('domains', row['folder'].to_s).gsub(/[^a-zA-Z0-9_\/\.-]/, '_')
175
- domain_name = row['domain_id'].to_s.gsub(/[^a-zA-Z0-9_\/\.-]/, '_')
176
- domains[domain_name] ||= {}
177
- domains[domain_name]["folder"] = folder
178
- domains[domain_name]["options"] ||= []
179
-
180
- hash = {}
181
- hash['value'] = row.delete('value').to_s
182
- hash['display_name'] = row.delete('display_name').to_s
183
- hash['description'] = row.delete('description').to_s
184
-
185
- domains[domain_name]["options"] << hash
186
- end
187
-
188
- domains.each do |domain_name, domain_hash|
189
- folder = domain_hash["folder"]
190
- FileUtils.mkpath folder
191
-
192
- file_name = File.join(folder, domain_name.to_s.downcase + '.json')
193
-
194
- File.open(file_name, 'w') do |file|
195
- file.write(JSON.pretty_generate(domain_hash["options"]) + "\n")
196
- end
197
- puts " create".colorize( :green ) + " #{file_name}"
198
- end
199
-
200
- end
201
-
202
- def additional_csv_info
203
- "\n\nFor additional information on specifying CSV column headers before import see:\n\n " + "https://github.com/sleepepi/spout#generate-a-new-repository-from-an-existing-csv-file".colorize( :light_cyan ) + "\n\n"
204
- end
@@ -1 +1 @@
1
- ruby-2.1.1
1
+ ruby-2.1.2
@@ -0,0 +1,2 @@
1
+ visit: visit
2
+ charts: []
data/lib/spout/version.rb CHANGED
@@ -3,7 +3,7 @@ module Spout
3
3
  MAJOR = 0
4
4
  MINOR = 8
5
5
  TINY = 0
6
- BUILD = "beta10" # nil, "pre", "rc", "rc2"
6
+ BUILD = "beta11" # nil, "pre", "rc", "rc2"
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, BUILD].compact.join('.')
9
9
  end
data/lib/spout.rb CHANGED
@@ -1,8 +1,115 @@
1
1
  require "spout/version"
2
- require "spout/actions"
3
2
  require "spout/application"
4
3
  require 'spout/tasks'
5
4
 
5
+ Spout::COMMANDS = {
6
+ 'n' => :new_project,
7
+ 'v' => :version,
8
+ 't' => :test,
9
+ 'i' => :importer,
10
+ 'e' => :exporter,
11
+ 'c' => :coverage_report,
12
+ 'p' => :generate_images,
13
+ 'g' => :generate_charts_and_tables,
14
+ 'o' => :outliers_report
15
+ }
16
+
6
17
  module Spout
18
+ def self.launch(argv)
19
+ self.send((Spout::COMMANDS[argv.first.to_s.scan(/\w/).first] || :help), argv)
20
+ end
21
+
22
+ def self.new_project(argv)
23
+ require 'spout/commands/project_generator'
24
+ Spout::Commands::ProjectGenerator.new(argv)
25
+ end
26
+
27
+ def self.coverage_report(argv)
28
+ require 'spout/commands/coverage'
29
+ Spout::Commands::Coverage.new(standard_version, argv)
30
+ end
31
+
32
+ def self.exporter(argv)
33
+ require 'spout/commands/exporter'
34
+ Spout::Commands::Exporter.new(standard_version, argv)
35
+ end
36
+
37
+ def self.generate_charts_and_tables(argv)
38
+ argv = argv.last(argv.size - 1)
39
+ require 'spout/commands/graphs'
40
+ variables = argv.collect{|s| s.to_s.downcase}
41
+ Spout::Commands::Graphs.new(variables, standard_version)
42
+ end
43
+
44
+ def self.generate_images(argv)
45
+ argv = argv.last(argv.size - 1)
46
+ require 'spout/commands/images'
47
+ types = flag_values(argv, 'type')
48
+ variable_ids = flag_values(argv, 'id')
49
+ sizes = flag_values(argv, 'size')
50
+ Spout::Commands::Images.new(types, variable_ids, sizes, standard_version, argv)
51
+ end
52
+
53
+ def self.help(argv)
54
+ puts <<-EOT
55
+
56
+ Usage: spout COMMAND [ARGS]
57
+
58
+ The most common spout commands are:
59
+ [n]ew Create a new Spout dictionary.
60
+ `spout new <project_name>` creates a new
61
+ data dictionary in `./<project_name>`
62
+ [t]est Run tests and show failing tests
63
+ [t] --verbose Run the tests and show passing and failing
64
+ tests
65
+ [i]mport Import a CSV file into the JSON dictionary
66
+ [e]xport [1.0.0] Export the JSON dictionary to CSV format
67
+ [c]overage Coverage report, requires dataset CSVs
68
+ in `<project_name>/csvs/<version>`
69
+ [o]utliers Outlier report, requires dataset CSVs
70
+ in `<project_name>/csvs/<version>`
71
+ [p]ngs Generates images for each variable in a
72
+ dataset and places them
73
+ in `<project_name>/images/<version>/`
74
+ [g]raphs Generates JSON graphs for each variable
75
+ in a dataset and places them
76
+ in `<project_name>/graphs/<version>/`
77
+ [v]ersion Returns the version of Spout
78
+
79
+ Commands can be referenced by the first letter:
80
+ Ex: `spout t`, for test
81
+
82
+ EOT
83
+ end
84
+
85
+ def self.importer(argv)
86
+ require 'spout/commands/importer'
87
+ Spout::Commands::Importer.new(argv)
88
+ end
89
+
90
+ def self.outliers_report(argv)
91
+ require 'spout/commands/outliers'
92
+ Spout::Commands::Outliers.new(standard_version, argv)
93
+ end
94
+
95
+ def self.test(argv)
96
+ hide_passing_tests = (argv.delete('--verbose') == nil)
97
+ system "bundle exec rake#{' HIDE_PASSING_TESTS=true' if hide_passing_tests}"
98
+ end
99
+
100
+ def self.version(argv)
101
+ puts "Spout #{Spout::VERSION::STRING}"
102
+ end
103
+
104
+ def self.standard_version
105
+ version = File.open('VERSION', &:readline).strip rescue ''
106
+ version == '' ? '1.0.0' : version
107
+ end
108
+
109
+ private
110
+
111
+ def self.flag_values(flags, param)
112
+ flags.select{|f| f[0..((param.size + 3) - 1)] == "--#{param}-" and f.length > param.size + 3}.collect{|f| f[(param.size + 3)..-1]}
113
+ end
7
114
 
8
115
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spout
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0.beta10
4
+ version: 0.8.0.beta11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Remo Mueller
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-02 00:00:00.000000000 Z
11
+ date: 2014-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -98,12 +98,16 @@ files:
98
98
  - lib/spout/actions.rb
99
99
  - lib/spout/application.rb
100
100
  - lib/spout/commands/coverage.rb
101
+ - lib/spout/commands/exporter.rb
101
102
  - lib/spout/commands/graphs.rb
102
103
  - lib/spout/commands/images.rb
104
+ - lib/spout/commands/importer.rb
103
105
  - lib/spout/commands/outliers.rb
106
+ - lib/spout/commands/project_generator.rb
104
107
  - lib/spout/helpers/array_statistics.rb
105
108
  - lib/spout/helpers/chart_types.rb
106
109
  - lib/spout/helpers/json_loader.rb
110
+ - lib/spout/helpers/number_helper.rb
107
111
  - lib/spout/helpers/subject_loader.rb
108
112
  - lib/spout/helpers/table_formatting.rb
109
113
  - lib/spout/hidden_reporter.rb
@@ -122,6 +126,7 @@ files:
122
126
  - lib/spout/templates/gitignore
123
127
  - lib/spout/templates/keep
124
128
  - lib/spout/templates/ruby-version
129
+ - lib/spout/templates/spout.yml
125
130
  - lib/spout/templates/test/dictionary_test.rb
126
131
  - lib/spout/templates/test/test_helper.rb
127
132
  - lib/spout/templates/travis.yml