spout 0.10.2 → 0.11.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/README.md +3 -30
  4. data/lib/spout/commands/coverage.rb +2 -1
  5. data/lib/spout/commands/deploy.rb +82 -77
  6. data/lib/spout/commands/exporter.rb +2 -3
  7. data/lib/spout/commands/graphs.rb +68 -67
  8. data/lib/spout/commands/help.rb +155 -0
  9. data/lib/spout/helpers/array_statistics.rb +36 -30
  10. data/lib/spout/helpers/chart_types.rb +2 -2
  11. data/lib/spout/helpers/config_reader.rb +5 -5
  12. data/lib/spout/helpers/json_request.rb +1 -2
  13. data/lib/spout/helpers/json_request_generic.rb +87 -0
  14. data/lib/spout/helpers/quietly.rb +2 -4
  15. data/lib/spout/helpers/semantic.rb +7 -11
  16. data/lib/spout/helpers/send_file.rb +23 -25
  17. data/lib/spout/helpers/subject_loader.rb +41 -32
  18. data/lib/spout/helpers/table_formatting.rb +7 -6
  19. data/lib/spout/models/bucket.rb +5 -4
  20. data/lib/spout/models/coverage_result.rb +1 -1
  21. data/lib/spout/models/dictionary.rb +3 -1
  22. data/lib/spout/models/domain.rb +7 -6
  23. data/lib/spout/models/empty.rb +17 -0
  24. data/lib/spout/models/form.rb +8 -5
  25. data/lib/spout/models/graphables/default.rb +41 -18
  26. data/lib/spout/models/graphables/histogram.rb +6 -7
  27. data/lib/spout/models/graphables.rb +3 -5
  28. data/lib/spout/models/option.rb +6 -2
  29. data/lib/spout/models/outlier_result.rb +3 -3
  30. data/lib/spout/models/record.rb +21 -3
  31. data/lib/spout/models/subject.rb +4 -7
  32. data/lib/spout/models/tables/choices_vs_choices.rb +29 -17
  33. data/lib/spout/models/tables/choices_vs_numeric.rb +19 -12
  34. data/lib/spout/models/tables/default.rb +19 -32
  35. data/lib/spout/models/tables/numeric_vs_choices.rb +9 -13
  36. data/lib/spout/models/tables/numeric_vs_numeric.rb +9 -11
  37. data/lib/spout/models/tables.rb +4 -6
  38. data/lib/spout/models/variable.rb +51 -13
  39. data/lib/spout/tasks/engine.rake +1 -1
  40. data/lib/spout/templates/ruby-version +1 -1
  41. data/lib/spout/templates/travis.yml +1 -1
  42. data/lib/spout/tests/domain_format.rb +2 -2
  43. data/lib/spout/tests/domain_name_format.rb +15 -0
  44. data/lib/spout/tests/form_name_format.rb +14 -0
  45. data/lib/spout/tests/variable_name_format.rb +14 -0
  46. data/lib/spout/tests.rb +18 -13
  47. data/lib/spout/version.rb +3 -3
  48. data/lib/spout/views/index.html.erb +2 -2
  49. data/lib/spout/views/outliers.html.erb +1 -1
  50. data/lib/spout.rb +13 -58
  51. data/spout.gemspec +14 -15
  52. metadata +25 -25
  53. data/lib/spout/commands/images.rb +0 -199
  54. data/lib/spout/support/javascripts/data.js +0 -17
  55. data/lib/spout/support/javascripts/highcharts-convert.js +0 -583
  56. data/lib/spout/support/javascripts/highcharts-more.js +0 -50
  57. data/lib/spout/support/javascripts/highstock.js +0 -353
  58. data/lib/spout/support/javascripts/jquery.1.9.1.min.js +0 -5
@@ -0,0 +1,87 @@
1
+ require 'openssl'
2
+ require 'net/http'
3
+ require 'json'
4
+ require 'cgi'
5
+
6
+ module Spout
7
+ module Helpers
8
+ class JsonRequestGeneric
9
+ class << self
10
+ def get(url, *args)
11
+ new(url, *args).get
12
+ end
13
+
14
+ def post(url, *args)
15
+ new(url, *args).post
16
+ end
17
+
18
+ def patch(url, *args)
19
+ new(url, *args).patch
20
+ end
21
+ end
22
+
23
+ attr_reader :url
24
+
25
+ def initialize(url, args = {})
26
+ @params = nested_hash_to_params(args)
27
+ @url = URI.parse(url)
28
+
29
+ @http = Net::HTTP.new(@url.host, @url.port)
30
+ if @url.scheme == 'https'
31
+ @http.use_ssl = true
32
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
33
+ end
34
+ rescue => e
35
+ puts "Error sending JsonRequestGeneric: #{e}".colorize(:red)
36
+ end
37
+
38
+ def get
39
+ full_path = @url.path
40
+ query = ([@url.query] + @params).flatten.compact.join('&')
41
+ full_path += "?#{query}" if query.to_s != ''
42
+ response = @http.start do |http|
43
+ http.get(full_path)
44
+ end
45
+ [JSON.parse(response.body), response]
46
+ rescue => e
47
+ puts "GET Error: #{e}".colorize(:red)
48
+ end
49
+
50
+ def post
51
+ response = @http.start do |http|
52
+ http.post(@url.path, @params.flatten.compact.join('&'))
53
+ end
54
+ [JSON.parse(response.body), response]
55
+ rescue => e
56
+ puts "POST ERROR: #{e}".colorize(:red)
57
+ nil
58
+ end
59
+
60
+ def patch
61
+ @params << '_method=patch'
62
+ post
63
+ end
64
+
65
+ def nested_hash_to_params(args)
66
+ args.collect do |key, value|
67
+ key_value_to_string(key, value, nil)
68
+ end
69
+ end
70
+
71
+ def key_value_to_string(key, value, scope = nil)
72
+ current_scope = (scope ? "#{scope}[#{key}]" : key)
73
+ if value.is_a? Hash
74
+ value.collect do |k,v|
75
+ key_value_to_string(k, v, current_scope)
76
+ end.join('&')
77
+ elsif value.is_a? Array
78
+ value.collect do |v|
79
+ key_value_to_string('', v, current_scope)
80
+ end
81
+ else
82
+ "#{current_scope}=#{CGI.escape(value.to_s)}"
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -1,12 +1,11 @@
1
-
2
1
  module Spout
3
2
  module Helpers
3
+ # Silences output for tests
4
4
  module Quietly
5
-
6
5
  # From Rails: http://apidock.com/rails/v3.2.13/Kernel/silence_stream
7
6
  def silence_stream(stream)
8
7
  old_stream = stream.dup
9
- stream.reopen(RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
8
+ stream.reopen(/mswin|mingw/ =~ RbConfig::CONFIG['host_os'] ? 'NUL:' : '/dev/null')
10
9
  stream.sync = true
11
10
  yield
12
11
  ensure
@@ -21,7 +20,6 @@ module Spout
21
20
  end
22
21
  end
23
22
  end
24
-
25
23
  end
26
24
  end
27
25
  end
@@ -1,9 +1,7 @@
1
- # def dataset_folders
2
- # Dir.entries('csvs').select{|e| File.directory? File.join('csvs', e) }.reject{|e| [".",".."].include?(e)}.sort
3
- # end
4
1
  module Spout
5
2
  module Helpers
6
-
3
+ # Helps to sort semantically versioned numbers to match versions that are
4
+ # close to each other.
7
5
  class Version
8
6
  attr_accessor :string
9
7
  attr_reader :major, :minor, :tiny, :build
@@ -26,7 +24,7 @@ module Spout
26
24
  end
27
25
 
28
26
  def build_number
29
- (@build == nil ? 1 : 0)
27
+ (@build.nil? ? 1 : 0)
30
28
  end
31
29
 
32
30
  def rank
@@ -34,21 +32,21 @@ module Spout
34
32
  end
35
33
  end
36
34
 
35
+ # Finds compatible versions
37
36
  class Semantic
38
-
39
37
  attr_accessor :data_dictionary_version
40
38
 
41
39
  def initialize(version, version_strings)
42
40
  @data_dictionary_version = Spout::Helpers::Version.new(version)
43
- @versions = version_strings.collect{ |vs| Spout::Helpers::Version.new(vs) }.sort_by(&:rank)
41
+ @versions = version_strings.collect { |vs| Spout::Helpers::Version.new(vs) }.sort_by(&:rank)
44
42
  end
45
43
 
46
44
  def valid_versions
47
- @versions.select{ |v| v.major == major and v.minor == minor }
45
+ @versions.select { |v| v.major == major && v.minor == minor }
48
46
  end
49
47
 
50
48
  def selected_folder
51
- if valid_versions.size == 0 or valid_versions.collect(&:string).include?(version)
49
+ if valid_versions.size == 0 || valid_versions.collect(&:string).include?(version)
52
50
  version
53
51
  else
54
52
  valid_versions.collect(&:string).last
@@ -74,8 +72,6 @@ module Spout
74
72
  def build
75
73
  @data_dictionary_version.build
76
74
  end
77
-
78
75
  end
79
-
80
76
  end
81
77
  end
@@ -13,15 +13,15 @@ module Spout
13
13
 
14
14
  attr_reader :url
15
15
 
16
- def initialize(url, filename, version, token, type = nil)
17
-
16
+ def initialize(url, filename, version, token, slug, folder)
18
17
  @params = {}
19
- @params["version"] = version
20
- @params["auth_token"] = token if token
21
- @params["type"] = type if type
18
+ @params['version'] = version
19
+ @params['auth_token'] = token if token
20
+ @params['dataset'] = slug if slug
21
+ @params['folder'] = folder if folder
22
22
  begin
23
- file = File.open(filename, "rb")
24
- @params["file"] = file
23
+ file = File.open(filename, 'rb')
24
+ @params['file'] = file
25
25
 
26
26
  mp = Multipart::MultipartPost.new
27
27
  @query, @headers = mp.prepare_query(@params)
@@ -42,36 +42,33 @@ module Spout
42
42
  end
43
43
 
44
44
  def post
45
- begin
46
- response = @http.start do |http|
47
- http.post(@url.path, @query, @headers)
48
- end
49
- JSON.parse(response.body)
50
- rescue
51
- nil
45
+ response = @http.start do |http|
46
+ http.post(@url.path, @query, @headers)
52
47
  end
48
+ JSON.parse(response.body)
49
+ rescue
50
+ nil
53
51
  end
54
52
  end
55
53
  end
56
54
  end
57
55
 
58
-
59
56
  module Multipart
60
57
  class Param
61
58
  attr_accessor :k, :v
62
- def initialize( k, v )
59
+ def initialize(k, v)
63
60
  @k = k
64
61
  @v = v
65
62
  end
66
63
 
67
64
  def to_multipart
68
- return "Content-Disposition: form-data; name=\"#{k}\"\r\n\r\n#{v}\r\n"
65
+ "Content-Disposition: form-data; name=\"#{k}\"\r\n\r\n#{v}\r\n"
69
66
  end
70
67
  end
71
68
 
72
69
  class FileParam
73
70
  attr_accessor :k, :filename, :content
74
- def initialize( k, filename, content )
71
+ def initialize(k, filename, content)
75
72
  @k = k
76
73
  @filename = filename
77
74
  @content = content
@@ -79,23 +76,24 @@ module Multipart
79
76
 
80
77
  def to_multipart
81
78
  mime_type = 'application/octet-stream'
82
- return "Content-Disposition: form-data; name=\"#{k}\"; filename=\"#{filename}\"\r\n" + "Content-Transfer-Encoding: binary\r\n" + "Content-Type: #{mime_type}\r\n\r\n" + content + "\r\n"
79
+ "Content-Disposition: form-data; name=\"#{k}\"; filename=\"#{filename}\"\r\n" + "Content-Transfer-Encoding: binary\r\n" + "Content-Type: #{mime_type}\r\n\r\n" + content + "\r\n"
83
80
  end
84
81
  end
82
+
85
83
  class MultipartPost
86
84
  BOUNDARY = 'a#41-93r1-^&#213-rule0000'
87
- HEADER = {"Content-type" => "multipart/form-data, boundary=" + BOUNDARY + " "}
85
+ HEADER = { 'Content-type' => "multipart/form-data, boundary=#{BOUNDARY} " }
88
86
 
89
- def prepare_query (params)
87
+ def prepare_query(params)
90
88
  fp = []
91
- params.each {|k,v|
89
+ params.each do |k, v|
92
90
  if v.respond_to?(:read)
93
91
  fp.push(FileParam.new(k, v.path, v.read))
94
92
  else
95
- fp.push(Param.new(k,v))
93
+ fp.push(Param.new(k, v))
96
94
  end
97
- }
98
- query = fp.collect {|p| "--" + BOUNDARY + "\r\n" + p.to_multipart }.join("") + "--" + BOUNDARY + "--"
95
+ end
96
+ query = fp.collect { |p| "--#{BOUNDARY}\r\n" + p.to_multipart }.join('') + "--#{BOUNDARY}--"
99
97
  return query, HEADER
100
98
  end
101
99
  end
@@ -4,6 +4,7 @@ require 'json'
4
4
 
5
5
  require 'spout/models/subject'
6
6
  require 'spout/helpers/semantic'
7
+ require 'spout/models/empty'
7
8
 
8
9
  module Spout
9
10
  module Helpers
@@ -32,74 +33,84 @@ module Spout
32
33
  def load_subjects_from_csvs_part_one!
33
34
  @subjects = []
34
35
 
35
- available_folders = (Dir.exist?('csvs') ? Dir.entries('csvs').select{|e| File.directory? File.join('csvs', e) }.reject{|e| [".",".."].include?(e)}.sort : [])
36
+ available_folders = (Dir.exist?('csvs') ? Dir.entries('csvs').select { |e| File.directory? File.join('csvs', e) }.reject { |e| ['.', '..'].include?(e) }.sort : [])
36
37
 
37
38
  @semantic = Spout::Helpers::Semantic.new(@standard_version, available_folders)
38
39
 
39
40
  @csv_directory = @semantic.selected_folder
40
41
 
41
- @csv_files = Dir.glob("csvs/#{@csv_directory}/*.csv")
42
- @csv_files.each_with_index do |csv_file, index|
42
+ csv_root = File.join('csvs', @csv_directory)
43
+ @csv_files = Dir.glob("#{csv_root}/**/*.csv").sort
44
+
45
+ if @csv_directory != @standard_version
46
+ puts "\n#{@csv_files.size == 0 ? 'No CSVs found' : 'Parsing files' } in " + "#{csv_root}".colorize(:white) + ' for dictionary version ' + @standard_version.to_s.colorize(:green) + "\n"
47
+ else
48
+ puts "\n#{@csv_files.size == 0 ? 'No CSVs found' : 'Parsing files' } in " + "#{csv_root}".colorize(:white) + "\n"
49
+ end
50
+
51
+ last_folder = nil
52
+ @csv_files.each do |csv_file|
53
+ relative_path = csv_file.gsub(%r{^#{csv_root}}, '')
54
+ current_file = File.basename(relative_path)
55
+ current_folder = relative_path.gsub(/#{current_file}$/, '')
43
56
  count = 1 # Includes counting the header row
44
- print "\nParsing #{csv_file}"
45
- 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|
57
+ puts " #{current_folder}".colorize(:white) if current_folder.to_s != '' && current_folder != last_folder
58
+ print " #{current_file}"
59
+ last_folder = current_folder
60
+ 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|
46
61
  row = line.to_hash
47
62
  count += 1
48
- print "\rParsing #{csv_file} - Row ##{count}" if (count % 10 == 0)
63
+ print "\r #{current_file} " + "##{count}".colorize(:yellow) if (count % 10 == 0)
49
64
  @subjects << Spout::Models::Subject.create do |t|
50
65
  t._visit = row[@visit]
66
+ t._csv = File.basename(csv_file)
51
67
 
52
- row.each do |key,value|
68
+ row.each do |key, value|
53
69
  method = key.to_s.downcase
54
-
70
+ next unless @valid_ids.include?(method) || @valid_ids.size == 0
55
71
  unless t.respond_to?(method)
56
72
  t.class.send(:define_method, "#{method}") { instance_variable_get("@#{method}") }
57
- t.class.send(:define_method, "#{method}=") { |value| instance_variable_set("@#{method}", value) }
73
+ t.class.send(:define_method, "#{method}=") { |v| instance_variable_set("@#{method}", v) }
58
74
  end
59
-
60
75
  @all_methods[method] ||= []
61
76
  @all_methods[method] = @all_methods[method] | [csv_file]
62
-
63
- unless value == nil
77
+ if value.nil?
78
+ t.send("#{method}=", Spout::Models::Empty.new)
79
+ else
64
80
  t.send("#{method}=", value)
65
81
  end
66
82
  end
67
83
  end
84
+
68
85
  # puts "Memory Used: " + (`ps -o rss -p #{$$}`.strip.split.last.to_i / 1024).to_s + " MB" if count % 1000 == 0
69
- break if @number_of_rows != nil and count - 1 >= @number_of_rows
86
+ break if !@number_of_rows.nil? && count - 1 >= @number_of_rows
70
87
  end
71
- print "\rParsing #{csv_file} - Row ##{count}"
72
- puts "\n"
73
- end
74
88
 
75
- if @csv_directory != @standard_version
76
- puts "#{@csv_files.size == 0 ? 'No CSVs found' : 'Using dataset' } in " + "csvs/#{@csv_directory}/".colorize( :green ) + " for dictionary version " + @standard_version.to_s.colorize( :green ) + "\n\n"
77
- else
78
- puts "#{@csv_files.size == 0 ? 'No CSVs found' : 'Using dataset' } in " + "csvs/#{@standard_version}/".colorize( :green ) + "\n\n"
89
+ print "\r #{current_file} " + "##{count}".colorize(:green)
90
+ puts "\n"
79
91
  end
80
-
81
92
  end
82
93
 
83
94
  def load_subjects_from_csvs_part_two!
84
95
  variable_count = @variable_files.count
85
- print "Converting numeric values to floats"
96
+ print 'Converting numeric values to floats'
86
97
  @variable_files.each_with_index do |variable_file, index|
87
- print "\rConverting numeric values to floats:#{"% 3d" % ((index+1)*100/variable_count)}%"
98
+ print "\rConverting numeric values to floats:#{'% 3d' % ((index + 1) * 100 / variable_count)}%"
88
99
  json = JSON.parse(File.read(variable_file)) rescue json = nil
89
100
  next unless json
90
- next unless @valid_ids.include?(json["id"].to_s.downcase) or @valid_ids.size == 0
91
- next unless ["numeric", "integer"].include?(json["type"])
92
- method = json['id'].to_s.downcase
101
+ next unless @valid_ids.include?(json['id'].to_s.downcase) || @valid_ids.size == 0
102
+ next unless %w(numeric integer).include?(json['type'])
103
+ method = json['id'].to_s.downcase
93
104
  next unless Spout::Models::Subject.method_defined?(method)
94
105
 
95
106
  domain_json = get_domain(json)
96
107
  # Make all domain options nil for numerics/integers
97
108
  if domain_json
98
- domain_values = domain_json.collect{|option_hash| option_hash['value']}
99
- @subjects.each{ |s| domain_values.include?(s.send(method)) ? s.send("#{method}=", nil) : nil }
109
+ domain_values = domain_json.collect { |option_hash| option_hash['value'] }
110
+ @subjects.each { |s| domain_values.include?(s.send(method)) ? s.send("#{method}=", nil) : nil }
100
111
  end
101
112
 
102
- @subjects.each{ |s| s.send(method) != nil ? s.send("#{method}=", s.send("#{method}").to_f) : nil }
113
+ @subjects.each { |s| !s.send(method).nil? ? s.send("#{method}=", s.send("#{method}").to_f) : nil }
103
114
  end
104
115
  puts "\n"
105
116
  @subjects
@@ -109,7 +120,7 @@ module Spout
109
120
  @variable_files.each do |variable_file|
110
121
  json = JSON.parse(File.read(variable_file)) rescue json = nil
111
122
  next unless json
112
- next unless ["choices"].include?(json["type"])
123
+ next unless ['choices'].include?(json['type'])
113
124
  domain = json['domain'].to_s.downcase
114
125
  @all_domains << domain
115
126
  end
@@ -129,8 +140,6 @@ module Spout
129
140
  def get_domain(json)
130
141
  get_json(json['domain'], 'domain')
131
142
  end
132
-
133
-
134
143
  end
135
144
  end
136
145
  end
@@ -1,18 +1,17 @@
1
1
  module Spout
2
2
  module Helpers
3
3
  class TableFormatting
4
-
5
4
  # def initialize(number)
6
5
  # @number = number
7
6
  # end
8
7
 
9
- def self.number_with_delimiter(number, delimiter = ",")
8
+ def self.number_with_delimiter(number, delimiter = ',')
10
9
  number.to_s.reverse.scan(/(?:\d*\.)?\d{1,3}-?/).join(',').reverse
11
10
  end
12
11
 
13
12
  # type: :count or :decimal
14
13
  def self.format_number(number, type, format = nil)
15
- if number == nil
14
+ if number.nil?
16
15
  format_nil(number)
17
16
  elsif type == :count
18
17
  format_count(number)
@@ -31,10 +30,9 @@ module Spout
31
30
  # 1000 -> '1,000'
32
31
  # Input (Numeric) -> Output (String)
33
32
  def self.format_count(number)
34
- (number == 0 || number == nil) ? '-' : number_with_delimiter(number)
33
+ (number == 0 || number.nil?) ? '-' : number_with_delimiter(number)
35
34
  end
36
35
 
37
-
38
36
  # decimal:
39
37
  # 0 -> '0.0'
40
38
  # 10 -> '10.0'
@@ -43,7 +41,10 @@ module Spout
43
41
  # 12412423.42252525 -> '12,412,423.4'
44
42
  # Input (Numeric) -> Output (String)
45
43
  def self.format_decimal(number, format)
46
- number = self.number_with_delimiter(number.round(1))
44
+ precision = 1
45
+ precision = -Math.log10(number.abs).floor if number.abs < 1.0 && number != 0
46
+
47
+ number = number_with_delimiter(number.round(precision))
47
48
  number = format % number if format
48
49
  number
49
50
  end
@@ -1,22 +1,23 @@
1
1
  module Spout
2
2
  module Models
3
+ # Defines a continuous or discrete bucket for tables and graphs
3
4
  class Bucket
4
-
5
5
  attr_accessor :start, :stop
6
6
 
7
- def initialize(start, stop)
7
+ def initialize(start, stop, discrete: false)
8
8
  @start = start
9
9
  @stop = stop
10
+ @discrete = discrete
10
11
  end
11
12
 
12
13
  def in_bucket?(value)
13
- value >= @start and value <= @stop
14
+ value >= @start && value <= @stop
14
15
  end
15
16
 
16
17
  def display_name
18
+ return "#{@start}" if @discrete
17
19
  "#{@start} to #{@stop}"
18
20
  end
19
-
20
21
  end
21
22
  end
22
23
  end
@@ -51,7 +51,7 @@ module Spout
51
51
  else
52
52
  domain_file = Dir.glob("domains/**/#{@json['domain'].to_s.downcase}.json", File::FNM_CASEFOLD).first
53
53
  if domain_json = JSON.parse(File.read(domain_file)) rescue false
54
- return domain_json.kind_of?(Array)
54
+ return domain_json.is_a?(Array)
55
55
  end
56
56
  false
57
57
  end
@@ -4,6 +4,8 @@ require 'spout/models/form'
4
4
 
5
5
  module Spout
6
6
  module Models
7
+ # Creates a structure that contains a dictionaries variables, domains, and
8
+ # forms
7
9
  class Dictionary
8
10
  attr_accessor :variables, :domains, :forms
9
11
  attr_accessor :app_path
@@ -44,7 +46,7 @@ module Spout
44
46
  private
45
47
 
46
48
  def json_files(type)
47
- Dir.glob(File.join(@app_path, type, "**", "*.json"))
49
+ Dir.glob(File.join(@app_path, type, '**', '*.json'))
48
50
  end
49
51
 
50
52
  def load_type!(method)
@@ -5,9 +5,7 @@ require 'spout/models/option'
5
5
 
6
6
  module Spout
7
7
  module Models
8
-
9
8
  class Domain < Spout::Models::Record
10
-
11
9
  attr_accessor :id, :folder, :options
12
10
  attr_reader :errors
13
11
 
@@ -26,11 +24,11 @@ module Spout
26
24
  nil
27
25
  end
28
26
  rescue => e
29
- @errors << "Parsing error found in #{@id}.json: #{e.message}" if file_name != nil
27
+ @errors << "Parsing error found in #{@id}.json: #{e.message}" unless file_name.nil?
30
28
  nil
31
29
  end
32
30
 
33
- if json and json.kind_of? Array
31
+ if json.is_a? Array
34
32
  @id = file_name.to_s.gsub(/^(.*)\/|\.json$/, '').downcase
35
33
  @options = (json || []).collect do |option|
36
34
  Spout::Models::Option.new(option)
@@ -38,10 +36,13 @@ module Spout
38
36
  elsif json
39
37
  @errors << "Domain must be a valid array in the following format: [\n {\n \"value\": \"1\",\n \"display_name\": \"First Choice\",\n \"description\": \"First Description\"\n },\n {\n \"value\": \"2\",\n \"display_name\": \"Second Choice\",\n \"description\": \"Second Description\"\n }\n]"
40
38
  end
41
-
42
39
  end
43
40
 
44
-
41
+ def deploy_params
42
+ { name: id, folder: folder.to_s.gsub(%r{/$}, ''),
43
+ options: options.collect(&:deploy_params),
44
+ spout_version: Spout::VERSION::STRING }
45
+ end
45
46
  end
46
47
  end
47
48
  end
@@ -0,0 +1,17 @@
1
+ module Spout
2
+ module Models
3
+ # Used for empty values, these values exist in that the column is defined
4
+ # in the CSV, however the cell is blank. This is to differentiate this
5
+ # value from nil, where the subject row exists, but the column for the
6
+ # is not specified.
7
+ class Empty
8
+ def to_f
9
+ self
10
+ end
11
+
12
+ def to_s
13
+ 'Empty'
14
+ end
15
+ end
16
+ end
17
+ end
@@ -9,8 +9,7 @@ require 'spout/models/record'
9
9
  module Spout
10
10
  module Models
11
11
  class Form < Spout::Models::Record
12
-
13
- attr_accessor :id, :display_name, :code_book
12
+ attr_accessor :id, :folder, :display_name, :code_book
14
13
  attr_accessor :errors
15
14
 
16
15
  def initialize(file_name, dictionary_root)
@@ -26,8 +25,8 @@ module Spout
26
25
  nil
27
26
  end
28
27
 
29
- if json and json.kind_of? Hash
30
- %w( display_name code_book ).each do |method|
28
+ if json.is_a? Hash
29
+ %w(display_name code_book).each do |method|
31
30
  instance_variable_set("@#{method}", json[method])
32
31
  end
33
32
 
@@ -35,9 +34,13 @@ module Spout
35
34
  elsif json
36
35
  @errors << "Form must be a valid hash in the following format: {\n\"id\": \"FORM_ID\",\n \"display_name\": \"FORM DISPLAY NAME\",\n \"code_book\": \"FORMPDF.pdf\"\n}"
37
36
  end
38
-
39
37
  end
40
38
 
39
+ def deploy_params
40
+ { name: id, folder: folder.to_s.gsub(%r{/$}, ''),
41
+ display_name: display_name, code_book: code_book,
42
+ spout_version: Spout::VERSION::STRING }
43
+ end
41
44
  end
42
45
  end
43
46
  end