spout 0.8.0.beta10 → 0.8.0.beta11

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 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