spout 0.10.2 → 0.11.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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