spout 0.12.1 → 0.13.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +5 -5
- data/Rakefile +4 -4
- data/bin/spout +1 -1
- data/lib/spout/commands/coverage.rb +18 -18
- data/lib/spout/commands/deploy.rb +89 -89
- data/lib/spout/commands/exporter.rb +16 -16
- data/lib/spout/commands/graphs.rb +37 -37
- data/lib/spout/commands/help.rb +1 -1
- data/lib/spout/commands/importer.rb +59 -57
- data/lib/spout/commands/outliers.rb +17 -17
- data/lib/spout/commands/project_generator.rb +25 -25
- data/lib/spout/commands/update.rb +38 -38
- data/lib/spout/helpers/array_statistics.rb +7 -7
- data/lib/spout/helpers/chart_types.rb +2 -2
- data/lib/spout/helpers/config_reader.rb +21 -20
- data/lib/spout/helpers/framework.rb +11 -11
- data/lib/spout/helpers/iterators.rb +1 -3
- data/lib/spout/helpers/json_loader.rb +2 -4
- data/lib/spout/helpers/json_request.rb +11 -11
- data/lib/spout/helpers/number_helper.rb +1 -1
- data/lib/spout/helpers/quietly.rb +1 -1
- data/lib/spout/helpers/semantic.rb +1 -1
- data/lib/spout/helpers/send_file.rb +14 -14
- data/lib/spout/helpers/subject_loader.rb +24 -24
- data/lib/spout/helpers/table_formatting.rb +12 -12
- data/lib/spout/models/coverage_result.rb +8 -8
- data/lib/spout/models/dictionary.rb +10 -10
- data/lib/spout/models/domain.rb +7 -7
- data/lib/spout/models/empty.rb +1 -1
- data/lib/spout/models/form.rb +6 -6
- data/lib/spout/models/graphables/choices_vs_choices.rb +3 -5
- data/lib/spout/models/graphables/choices_vs_numeric.rb +4 -6
- data/lib/spout/models/graphables/default.rb +6 -6
- data/lib/spout/models/graphables/histogram.rb +4 -4
- data/lib/spout/models/graphables/numeric_vs_choices.rb +1 -1
- data/lib/spout/models/graphables/numeric_vs_numeric.rb +6 -6
- data/lib/spout/models/graphables.rb +14 -14
- data/lib/spout/models/outlier_result.rb +16 -18
- data/lib/spout/models/record.rb +3 -3
- data/lib/spout/models/tables/choices_vs_choices.rb +11 -11
- data/lib/spout/models/tables/choices_vs_numeric.rb +8 -8
- data/lib/spout/models/tables/default.rb +5 -5
- data/lib/spout/models/tables/numeric_vs_choices.rb +7 -7
- data/lib/spout/models/tables/numeric_vs_numeric.rb +7 -7
- data/lib/spout/models/tables.rb +11 -11
- data/lib/spout/models/variable.rb +14 -14
- data/lib/spout/tasks/engine.rake +4 -4
- data/lib/spout/templates/CHANGELOG.md.erb +1 -1
- data/lib/spout/templates/Gemfile +2 -2
- data/lib/spout/templates/Rakefile +1 -1
- data/lib/spout/templates/test/dictionary_test.rb +3 -3
- data/lib/spout/templates/test/test_helper.rb +1 -1
- data/lib/spout/tests/domain_existence_validation.rb +6 -6
- data/lib/spout/tests/domain_format.rb +1 -1
- data/lib/spout/tests/domain_name_format.rb +3 -3
- data/lib/spout/tests/domain_name_uniqueness.rb +2 -2
- data/lib/spout/tests/domain_specified.rb +1 -3
- data/lib/spout/tests/form_existence_validation.rb +2 -4
- data/lib/spout/tests/form_name_format.rb +3 -3
- data/lib/spout/tests/form_name_match.rb +1 -1
- data/lib/spout/tests/json_helper.rb +1 -1
- data/lib/spout/tests/json_validation.rb +0 -2
- data/lib/spout/tests/variable_name_format.rb +3 -3
- data/lib/spout/tests/variable_name_match.rb +1 -3
- data/lib/spout/tests/variable_name_uniqueness.rb +2 -2
- data/lib/spout/tests/variable_type_validation.rb +2 -2
- data/lib/spout/tests.rb +30 -30
- data/lib/spout/version.rb +4 -4
- data/lib/spout/views/index.html.erb +15 -15
- data/lib/spout/views/outliers.html.erb +8 -8
- data/lib/spout.rb +26 -26
- data/spout.gemspec +22 -22
- metadata +5 -5
@@ -7,8 +7,8 @@ module Spout
|
|
7
7
|
# @number = number
|
8
8
|
# end
|
9
9
|
|
10
|
-
def self.number_with_delimiter(number, delimiter =
|
11
|
-
number.to_s.reverse.scan(/(?:\d*\.)?\d{1,3}-?/).join(
|
10
|
+
def self.number_with_delimiter(number, delimiter = ",")
|
11
|
+
number.to_s.reverse.scan(/(?:\d*\.)?\d{1,3}-?/).join(",").reverse
|
12
12
|
end
|
13
13
|
|
14
14
|
# type: :count or :decimal
|
@@ -23,24 +23,24 @@ module Spout
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def self.format_nil(number)
|
26
|
-
|
26
|
+
"-"
|
27
27
|
end
|
28
28
|
|
29
29
|
# count:
|
30
|
-
# 0 ->
|
31
|
-
# 10 ->
|
32
|
-
# 1000 ->
|
30
|
+
# 0 -> "-"
|
31
|
+
# 10 -> "10"
|
32
|
+
# 1000 -> "1,000"
|
33
33
|
# Input (Numeric) -> Output (String)
|
34
34
|
def self.format_count(number)
|
35
|
-
(number == 0 || number.nil?) ?
|
35
|
+
(number == 0 || number.nil?) ? "-" : number_with_delimiter(number)
|
36
36
|
end
|
37
37
|
|
38
38
|
# decimal:
|
39
|
-
# 0 ->
|
40
|
-
# 10 ->
|
41
|
-
# -50.2555 ->
|
42
|
-
# 1000 ->
|
43
|
-
# 12412423.42252525 ->
|
39
|
+
# 0 -> "0.0"
|
40
|
+
# 10 -> "10.0"
|
41
|
+
# -50.2555 -> "-50.3"
|
42
|
+
# 1000 -> "1,000.0"
|
43
|
+
# 12412423.42252525 -> "12,412,423.4"
|
44
44
|
# Input (Numeric) -> Output (String)
|
45
45
|
def self.format_decimal(number, format)
|
46
46
|
precision = 1
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spout/tests/variable_type_validation"
|
4
4
|
|
5
5
|
module Spout
|
6
6
|
module Models
|
@@ -24,15 +24,15 @@ module Spout
|
|
24
24
|
file = Dir.glob("variables/**/#{column.to_s.downcase}.json", File::FNM_CASEFOLD).first
|
25
25
|
@file_name_test = !file.nil?
|
26
26
|
@json = JSON.parse(File.read(file)) rescue @json = {}
|
27
|
-
@json_id_test = (@json[
|
27
|
+
@json_id_test = (@json["id"].to_s.downcase == column)
|
28
28
|
end
|
29
29
|
|
30
30
|
def load_valid_values
|
31
31
|
valid_values = []
|
32
|
-
if @json[
|
32
|
+
if @json["type"] == "choices" || domain_name != ""
|
33
33
|
file = Dir.glob("domains/**/#{@json['domain'].to_s.downcase}.json", File::FNM_CASEFOLD).first
|
34
34
|
if json = JSON.parse(File.read(file)) rescue false
|
35
|
-
valid_values = json.collect { |hash| hash[
|
35
|
+
valid_values = json.collect { |hash| hash["value"] }
|
36
36
|
end
|
37
37
|
end
|
38
38
|
@valid_values = valid_values
|
@@ -43,15 +43,15 @@ module Spout
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def check_values
|
46
|
-
@json[
|
46
|
+
@json["type"] != "choices" || (@valid_values | @csv_values.compact).size == @valid_values.size
|
47
47
|
end
|
48
48
|
|
49
49
|
def check_variable_type
|
50
|
-
Spout::Tests::VariableTypeValidation::VALID_VARIABLE_TYPES.include?(@json[
|
50
|
+
Spout::Tests::VariableTypeValidation::VALID_VARIABLE_TYPES.include?(@json["type"])
|
51
51
|
end
|
52
52
|
|
53
53
|
def check_domain_specified
|
54
|
-
if @json[
|
54
|
+
if @json["type"] != "choices" && domain_name == ""
|
55
55
|
true
|
56
56
|
else
|
57
57
|
domain_file = Dir.glob("domains/**/#{@json['domain'].to_s.downcase}.json", File::FNM_CASEFOLD).first
|
@@ -67,7 +67,7 @@ module Spout
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def domain_name
|
70
|
-
@json[
|
70
|
+
@json["domain"].to_s.downcase.strip
|
71
71
|
end
|
72
72
|
end
|
73
73
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "spout/models/variable"
|
4
|
+
require "spout/models/domain"
|
5
|
+
require "spout/models/form"
|
6
6
|
|
7
7
|
module Spout
|
8
8
|
module Models
|
@@ -17,9 +17,9 @@ module Spout
|
|
17
17
|
def initialize(app_path)
|
18
18
|
@app_path = app_path
|
19
19
|
|
20
|
-
@variable_files = json_files(
|
21
|
-
@domain_files = json_files(
|
22
|
-
@form_files = json_files(
|
20
|
+
@variable_files = json_files("variables")
|
21
|
+
@domain_files = json_files("domains")
|
22
|
+
@form_files = json_files("forms")
|
23
23
|
|
24
24
|
@variables = []
|
25
25
|
@domains = []
|
@@ -34,21 +34,21 @@ module Spout
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def load_variables!
|
37
|
-
load_type!(
|
37
|
+
load_type!("Variable")
|
38
38
|
end
|
39
39
|
|
40
40
|
def load_domains!
|
41
|
-
load_type!(
|
41
|
+
load_type!("Domain")
|
42
42
|
end
|
43
43
|
|
44
44
|
def load_forms!
|
45
|
-
load_type!(
|
45
|
+
load_type!("Form")
|
46
46
|
end
|
47
47
|
|
48
48
|
private
|
49
49
|
|
50
50
|
def json_files(type)
|
51
|
-
Dir.glob(File.join(@app_path, type,
|
51
|
+
Dir.glob(File.join(@app_path, type, "**", "*.json"))
|
52
52
|
end
|
53
53
|
|
54
54
|
def load_type!(method)
|
data/lib/spout/models/domain.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "json"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
5
|
+
require "spout/models/record"
|
6
|
+
require "spout/models/option"
|
7
7
|
|
8
8
|
module Spout
|
9
9
|
module Models
|
@@ -13,9 +13,9 @@ module Spout
|
|
13
13
|
|
14
14
|
def initialize(file_name, dictionary_root)
|
15
15
|
@errors = []
|
16
|
-
@id = file_name.to_s.gsub(/^(.*)\/|\.json$/,
|
16
|
+
@id = file_name.to_s.gsub(/^(.*)\/|\.json$/, "").downcase
|
17
17
|
|
18
|
-
@folder = file_name.to_s.gsub(/^#{dictionary_root}\/domains\/|#{@id}\.json$/,
|
18
|
+
@folder = file_name.to_s.gsub(/^#{dictionary_root}\/domains\/|#{@id}\.json$/, "")
|
19
19
|
@options = []
|
20
20
|
|
21
21
|
json = begin
|
@@ -31,7 +31,7 @@ module Spout
|
|
31
31
|
end
|
32
32
|
|
33
33
|
if json.is_a? Array
|
34
|
-
@id = file_name.to_s.gsub(/^(.*)\/|\.json$/,
|
34
|
+
@id = file_name.to_s.gsub(/^(.*)\/|\.json$/, "").downcase
|
35
35
|
@options = (json || []).collect do |option|
|
36
36
|
Spout::Models::Option.new(option)
|
37
37
|
end
|
@@ -41,7 +41,7 @@ module Spout
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def deploy_params
|
44
|
-
{ name: id, folder: folder.to_s.gsub(%r{/$},
|
44
|
+
{ name: id, folder: folder.to_s.gsub(%r{/$}, ""),
|
45
45
|
options: options.collect(&:deploy_params),
|
46
46
|
spout_version: Spout::VERSION::STRING }
|
47
47
|
end
|
data/lib/spout/models/empty.rb
CHANGED
data/lib/spout/models/form.rb
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
# "code_book": "Baseline-Visit-Intake-Questionnaire.pdf"
|
7
7
|
# }
|
8
8
|
|
9
|
-
require
|
9
|
+
require "spout/models/record"
|
10
10
|
|
11
11
|
module Spout
|
12
12
|
module Models
|
@@ -16,13 +16,13 @@ module Spout
|
|
16
16
|
|
17
17
|
def initialize(file_name, dictionary_root)
|
18
18
|
@errors = []
|
19
|
-
@id = file_name.to_s.gsub(/^(.*)\/|\.json$/,
|
20
|
-
@folder = file_name.to_s.gsub(/^#{dictionary_root}\/forms\/|#{@id}\.json$/,
|
19
|
+
@id = file_name.to_s.gsub(/^(.*)\/|\.json$/, "").downcase
|
20
|
+
@folder = file_name.to_s.gsub(/^#{dictionary_root}\/forms\/|#{@id}\.json$/, "")
|
21
21
|
|
22
22
|
json = begin
|
23
23
|
JSON.parse(File.read(file_name))
|
24
24
|
rescue => e
|
25
|
-
form_name = file_name.to_s.gsub(/^(.*)\/|\.json$/,
|
25
|
+
form_name = file_name.to_s.gsub(/^(.*)\/|\.json$/, "").downcase
|
26
26
|
@errors << "Error Parsing #{form_name}.json: #{e.message}"
|
27
27
|
nil
|
28
28
|
end
|
@@ -32,14 +32,14 @@ module Spout
|
|
32
32
|
instance_variable_set("@#{method}", json[method])
|
33
33
|
end
|
34
34
|
|
35
|
-
@errors << "'id': #{json['id'].inspect} does not match filename #{@id.inspect}" if @id != json[
|
35
|
+
@errors << "'id': #{json['id'].inspect} does not match filename #{@id.inspect}" if @id != json["id"]
|
36
36
|
elsif json
|
37
37
|
@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}"
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
def deploy_params
|
42
|
-
{ name: id, folder: folder.to_s.gsub(%r{/$},
|
42
|
+
{ name: id, folder: folder.to_s.gsub(%r{/$}, ""),
|
43
43
|
display_name: display_name, code_book: code_book,
|
44
44
|
spout_version: Spout::VERSION::STRING }
|
45
45
|
end
|
@@ -1,18 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spout/models/graphables/default"
|
4
4
|
|
5
5
|
module Spout
|
6
6
|
module Models
|
7
7
|
module Graphables
|
8
8
|
class ChoicesVsChoices < Spout::Models::Graphables::Default
|
9
|
-
|
10
9
|
def categories
|
11
10
|
filtered_domain_options(@chart_variable).collect(&:display_name)
|
12
11
|
end
|
13
12
|
|
14
13
|
def units
|
15
|
-
|
14
|
+
"percent"
|
16
15
|
end
|
17
16
|
|
18
17
|
def series
|
@@ -26,9 +25,8 @@ module Spout
|
|
26
25
|
end
|
27
26
|
|
28
27
|
def stacking
|
29
|
-
|
28
|
+
"percent"
|
30
29
|
end
|
31
|
-
|
32
30
|
end
|
33
31
|
end
|
34
32
|
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "spout/models/graphables/default"
|
4
|
+
require "spout/helpers/array_statistics"
|
5
5
|
|
6
6
|
module Spout
|
7
7
|
module Models
|
8
8
|
module Graphables
|
9
9
|
class ChoicesVsNumeric < Spout::Models::Graphables::Default
|
10
|
-
|
11
10
|
def categories
|
12
11
|
filtered_subjects = filter_and_sort_subjects
|
13
12
|
|
@@ -20,7 +19,7 @@ module Spout
|
|
20
19
|
end
|
21
20
|
|
22
21
|
def units
|
23
|
-
|
22
|
+
"percent"
|
24
23
|
end
|
25
24
|
|
26
25
|
def series
|
@@ -37,7 +36,7 @@ module Spout
|
|
37
36
|
end
|
38
37
|
|
39
38
|
def stacking
|
40
|
-
|
39
|
+
"percent"
|
41
40
|
end
|
42
41
|
|
43
42
|
private
|
@@ -51,7 +50,6 @@ module Spout
|
|
51
50
|
[]
|
52
51
|
end
|
53
52
|
end
|
54
|
-
|
55
53
|
end
|
56
54
|
end
|
57
55
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "spout/models/variable"
|
4
|
+
require "spout/models/bucket"
|
5
5
|
|
6
6
|
module Spout
|
7
7
|
module Models
|
@@ -29,9 +29,9 @@ module Spout
|
|
29
29
|
def valid?
|
30
30
|
if @variable.nil? || @chart_variable.nil? || @values_unique == []
|
31
31
|
false
|
32
|
-
elsif @variable.type ==
|
32
|
+
elsif @variable.type == "choices" && @variable.domain.options == []
|
33
33
|
false
|
34
|
-
elsif @chart_variable.type ==
|
34
|
+
elsif @chart_variable.type == "choices" && @chart_variable.domain.options == []
|
35
35
|
false
|
36
36
|
else
|
37
37
|
true
|
@@ -43,7 +43,7 @@ module Spout
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def subtitle
|
46
|
-
|
46
|
+
"By Visit"
|
47
47
|
end
|
48
48
|
|
49
49
|
def categories
|
@@ -110,7 +110,7 @@ module Spout
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def all_integer?(values_numeric)
|
113
|
-
count = values_numeric.count { |v| Integer(format(
|
113
|
+
count = values_numeric.count { |v| Integer(format("%.0f", v)) == v }
|
114
114
|
count == values_numeric.size
|
115
115
|
end
|
116
116
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spout/models/graphables/default"
|
4
4
|
|
5
5
|
module Spout
|
6
6
|
module Models
|
@@ -12,7 +12,7 @@ module Spout
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def categories
|
15
|
-
if @variable.type ==
|
15
|
+
if @variable.type == "choices"
|
16
16
|
filtered_domain_options(@variable).collect(&:display_name)
|
17
17
|
else
|
18
18
|
@buckets.collect(&:display_name)
|
@@ -20,7 +20,7 @@ module Spout
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def units
|
23
|
-
|
23
|
+
"Subjects"
|
24
24
|
end
|
25
25
|
|
26
26
|
def series
|
@@ -31,7 +31,7 @@ module Spout
|
|
31
31
|
|
32
32
|
data = []
|
33
33
|
|
34
|
-
if @variable.type ==
|
34
|
+
if @variable.type == "choices"
|
35
35
|
data = filtered_domain_options(@variable).collect do |o|
|
36
36
|
visit_subject_values.select { |v| v == o.value }.count
|
37
37
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "spout/models/graphables/default"
|
4
|
+
require "spout/helpers/array_statistics"
|
5
5
|
|
6
6
|
module Spout
|
7
7
|
module Models
|
@@ -44,10 +44,10 @@ module Spout
|
|
44
44
|
|
45
45
|
def array_statistics(array)
|
46
46
|
{ y: (array.mean.round(1) rescue 0.0),
|
47
|
-
stddev: ("%0.1f" % array.standard_deviation rescue
|
48
|
-
median: ("%0.1f" % array.median rescue
|
49
|
-
min: ("%0.1f" % array.min rescue
|
50
|
-
max: ("%0.1f" % array.max rescue
|
47
|
+
stddev: ("%0.1f" % array.standard_deviation rescue ""),
|
48
|
+
median: ("%0.1f" % array.median rescue ""),
|
49
|
+
min: ("%0.1f" % array.min rescue ""),
|
50
|
+
max: ("%0.1f" % array.max rescue ""),
|
51
51
|
n: array.n }
|
52
52
|
end
|
53
53
|
|
@@ -1,22 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
3
|
+
require "spout/models/graphables/default"
|
4
|
+
require "spout/models/graphables/histogram"
|
5
|
+
require "spout/models/graphables/numeric_vs_choices"
|
6
|
+
require "spout/models/graphables/choices_vs_choices"
|
7
|
+
require "spout/models/graphables/numeric_vs_numeric"
|
8
|
+
require "spout/models/graphables/choices_vs_numeric"
|
9
9
|
|
10
10
|
module Spout
|
11
11
|
module Models
|
12
12
|
module Graphables
|
13
13
|
DEFAULT_CLASS = Spout::Models::Graphables::Default
|
14
14
|
GRAPHABLE_CLASSES = {
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
"histogram" => Spout::Models::Graphables::Histogram,
|
16
|
+
"numeric_vs_choices" => Spout::Models::Graphables::NumericVsChoices,
|
17
|
+
"choices_vs_choices" => Spout::Models::Graphables::ChoicesVsChoices,
|
18
|
+
"numeric_vs_numeric" => Spout::Models::Graphables::NumericVsNumeric,
|
19
|
+
"choices_vs_numeric" => Spout::Models::Graphables::ChoicesVsNumeric
|
20
20
|
}
|
21
21
|
|
22
22
|
def self.for(variable, chart_variable, stratification_variable, subjects)
|
@@ -26,7 +26,7 @@ module Spout
|
|
26
26
|
|
27
27
|
def self.get_graph_type(variable, chart_variable, stratification_variable)
|
28
28
|
if stratification_variable.nil?
|
29
|
-
|
29
|
+
"histogram"
|
30
30
|
else
|
31
31
|
"#{variable_to_graph_type(variable)}_vs_#{variable_to_graph_type(chart_variable)}"
|
32
32
|
end
|
@@ -35,8 +35,8 @@ module Spout
|
|
35
35
|
def self.variable_to_graph_type(variable)
|
36
36
|
variable_type = (variable ? variable.type : nil)
|
37
37
|
case variable_type
|
38
|
-
when
|
39
|
-
|
38
|
+
when "numeric", "integer"
|
39
|
+
"numeric"
|
40
40
|
else
|
41
41
|
variable_type
|
42
42
|
end
|
@@ -1,32 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "spout/helpers/array_statistics"
|
4
|
+
require "spout/helpers/json_loader"
|
5
5
|
|
6
6
|
module Spout
|
7
7
|
module Models
|
8
8
|
class OutlierResult
|
9
|
-
attr_reader :csv_files, :method, :major_outliers, :minor_outliers,
|
9
|
+
attr_reader :csv_files, :method, :major_outliers, :minor_outliers,
|
10
|
+
:outliers, :weight, :units, :display_name, :median,
|
11
|
+
:variable_type
|
10
12
|
|
11
13
|
def initialize(subjects, method, csv_files)
|
12
14
|
@values = subjects.collect(&method.to_sym)
|
13
15
|
@csv_files = csv_files
|
14
16
|
@method = method
|
15
|
-
|
16
|
-
|
17
17
|
calculate_outliers!
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
18
|
+
@weight = \
|
19
|
+
if @major_outliers.count > 0
|
20
|
+
0
|
21
|
+
elsif @minor_outliers.count > 0
|
22
|
+
1
|
23
|
+
else
|
24
|
+
2
|
25
|
+
end
|
26
26
|
variable = Spout::Helpers::JsonLoader::get_variable(method)
|
27
|
-
@units = (variable.is_a?(Hash) ? variable[
|
28
|
-
@display_name = (variable.is_a?(Hash) ? variable[
|
29
|
-
@variable_type = (variable.is_a?(Hash) ? variable[
|
27
|
+
@units = (variable.is_a?(Hash) ? variable["units"] : nil)
|
28
|
+
@display_name = (variable.is_a?(Hash) ? variable["display_name"] : nil)
|
29
|
+
@variable_type = (variable.is_a?(Hash) ? variable["type"] : nil)
|
30
30
|
@median = @values.median
|
31
31
|
end
|
32
32
|
|
@@ -35,8 +35,6 @@ module Spout
|
|
35
35
|
@minor_outliers = @values.minor_outliers.uniq
|
36
36
|
@outliers = @values.outliers.uniq
|
37
37
|
end
|
38
|
-
|
39
38
|
end
|
40
|
-
|
41
39
|
end
|
42
40
|
end
|
data/lib/spout/models/record.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "json"
|
4
|
+
require "fileutils"
|
5
5
|
|
6
6
|
module Spout
|
7
7
|
module Models
|
@@ -27,7 +27,7 @@ module Spout
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def expected_path(id)
|
30
|
-
File.join(dictionary_root, record_folder,
|
30
|
+
File.join(dictionary_root, record_folder, "**", expected_filename(id))
|
31
31
|
end
|
32
32
|
|
33
33
|
def dictionary_root
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spout/models/tables/default"
|
4
4
|
|
5
5
|
module Spout
|
6
6
|
module Models
|
@@ -12,9 +12,9 @@ module Spout
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def headers
|
15
|
-
header_row = [
|
15
|
+
header_row = [""] + filtered_domain_options(@chart_variable).collect(&:display_name)
|
16
16
|
if @totals
|
17
|
-
header_row += [
|
17
|
+
header_row += ["Total"]
|
18
18
|
end
|
19
19
|
[header_row]
|
20
20
|
end
|
@@ -22,11 +22,11 @@ module Spout
|
|
22
22
|
def footers
|
23
23
|
total_values = filtered_domain_options(@chart_variable).collect do |option|
|
24
24
|
total_count = @filtered_subjects.count { |s| s.send(@chart_variable.id) == option.value }
|
25
|
-
{ text: (Spout::Helpers::TableFormatting.format_number(total_count, :count)), style:
|
25
|
+
{ text: (Spout::Helpers::TableFormatting.format_number(total_count, :count)), style: "font-weight:bold" }
|
26
26
|
end
|
27
|
-
footer_row = [{ text:
|
27
|
+
footer_row = [{ text: "Total", style: "font-weight:bold" }] + total_values
|
28
28
|
if @totals
|
29
|
-
footer_row += [{ text: Spout::Helpers::TableFormatting.format_number(@filtered_subjects.count, :count), style:
|
29
|
+
footer_row += [{ text: Spout::Helpers::TableFormatting.format_number(@filtered_subjects.count, :count), style: "font-weight:bold" }]
|
30
30
|
end
|
31
31
|
[footer_row]
|
32
32
|
end
|
@@ -36,25 +36,25 @@ module Spout
|
|
36
36
|
row_subjects = @filtered_subjects.select { |s| s.send(@variable.id) == option.value }
|
37
37
|
row_cells = filtered_domain_options(@chart_variable).collect do |chart_option|
|
38
38
|
count = row_subjects.count { |s| s.send(@chart_variable.id) == chart_option.value }
|
39
|
-
count > 0 ? Spout::Helpers::TableFormatting.format_number(count, :count) : { text:
|
39
|
+
count > 0 ? Spout::Helpers::TableFormatting.format_number(count, :count) : { text: "-", class: "text-muted" }
|
40
40
|
end
|
41
41
|
|
42
42
|
row = [option.display_name] + row_cells
|
43
43
|
|
44
44
|
if @totals
|
45
45
|
total = row_subjects.count
|
46
|
-
row += [total == 0 ? { text:
|
46
|
+
row += [total == 0 ? { text: "-", class: "text-muted" } : { text: Spout::Helpers::TableFormatting.format_number(total, :count), style: "font-weight:bold" }]
|
47
47
|
end
|
48
48
|
row
|
49
49
|
end
|
50
50
|
|
51
51
|
if @filtered_subjects.count { |s| s.send(@variable.id).is_a?(Spout::Models::Empty) } > 0
|
52
52
|
unknown_values = filtered_domain_options(@chart_variable).collect do |chart_option|
|
53
|
-
{ text: Spout::Helpers::TableFormatting.format_number(@filtered_subjects.count { |s| s.send(@chart_variable.id) == chart_option.value && s.send(@variable.id).is_a?(Spout::Models::Empty) }, :count), class:
|
53
|
+
{ text: Spout::Helpers::TableFormatting.format_number(@filtered_subjects.count { |s| s.send(@chart_variable.id) == chart_option.value && s.send(@variable.id).is_a?(Spout::Models::Empty) }, :count), class: "text-muted" }
|
54
54
|
end
|
55
|
-
unknown_row = [{ text:
|
55
|
+
unknown_row = [{ text: "Unknown", class: "text-muted" }] + unknown_values
|
56
56
|
if @totals
|
57
|
-
unknown_row += [{ text: Spout::Helpers::TableFormatting.format_number(@filtered_subjects.count { |s| s.send(@variable.id).is_a?(Spout::Models::Empty) }, :count), style:
|
57
|
+
unknown_row += [{ text: Spout::Helpers::TableFormatting.format_number(@filtered_subjects.count { |s| s.send(@variable.id).is_a?(Spout::Models::Empty) }, :count), style: "font-weight:bold", class: "text-muted" }]
|
58
58
|
end
|
59
59
|
rows_result << unknown_row
|
60
60
|
end
|