marty 2.5.2 → 2.5.4

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 (181) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +4 -0
  3. data/.rubocop.yml +7 -0
  4. data/.rubocop_todo.yml +11 -589
  5. data/Gemfile +9 -9
  6. data/Gemfile.lock +1 -1
  7. data/Rakefile +1 -3
  8. data/app/components/marty/api_auth_view.rb +3 -3
  9. data/app/components/marty/api_config_view.rb +8 -8
  10. data/app/components/marty/api_log_view.rb +16 -20
  11. data/app/components/marty/auth_app.rb +6 -6
  12. data/app/components/marty/base_rule_view.rb +27 -19
  13. data/app/components/marty/config_view.rb +12 -9
  14. data/app/components/marty/data_grid_view.rb +26 -26
  15. data/app/components/marty/delorean_rule_view.rb +0 -1
  16. data/app/components/marty/event_view.rb +27 -27
  17. data/app/components/marty/extras/layout.rb +26 -26
  18. data/app/components/marty/extras/misc.rb +2 -2
  19. data/app/components/marty/grid.rb +13 -13
  20. data/app/components/marty/grid_append_only.rb +0 -1
  21. data/app/components/marty/import_type_view.rb +13 -13
  22. data/app/components/marty/import_view.rb +17 -16
  23. data/app/components/marty/log_view.rb +16 -14
  24. data/app/components/marty/main_auth_app.rb +59 -59
  25. data/app/components/marty/main_auth_app/client/main_auth_app.js +3 -3
  26. data/app/components/marty/mcfly_grid_panel.rb +10 -10
  27. data/app/components/marty/new_posting_form.rb +11 -11
  28. data/app/components/marty/new_posting_window.rb +0 -1
  29. data/app/components/marty/posting_grid.rb +12 -13
  30. data/app/components/marty/promise_view.rb +6 -6
  31. data/app/components/marty/report_form.rb +50 -53
  32. data/app/components/marty/report_select.rb +27 -27
  33. data/app/components/marty/reporting.rb +4 -4
  34. data/app/components/marty/script_form.rb +40 -42
  35. data/app/components/marty/script_grid.rb +24 -24
  36. data/app/components/marty/script_tester.rb +40 -42
  37. data/app/components/marty/scripting.rb +25 -27
  38. data/app/components/marty/simple_app.rb +24 -9
  39. data/app/components/marty/tag_grid.rb +12 -13
  40. data/app/components/marty/user_view.rb +35 -35
  41. data/app/controllers/marty/application_controller.rb +3 -4
  42. data/app/controllers/marty/components_controller.rb +1 -1
  43. data/app/controllers/marty/delayed_job_controller.rb +1 -0
  44. data/app/controllers/marty/diagnostic/controller.rb +4 -6
  45. data/app/controllers/marty/job_controller.rb +6 -6
  46. data/app/controllers/marty/report_controller.rb +11 -11
  47. data/app/controllers/marty/rpc_controller.rb +15 -16
  48. data/app/helpers/marty/script_set.rb +4 -4
  49. data/app/models/marty/api_auth.rb +4 -5
  50. data/app/models/marty/api_config.rb +1 -1
  51. data/app/models/marty/base.rb +9 -8
  52. data/app/models/marty/base_rule.rb +18 -13
  53. data/app/models/marty/config.rb +4 -5
  54. data/app/models/marty/data_grid.rb +157 -181
  55. data/app/models/marty/delorean_rule.rb +63 -62
  56. data/app/models/marty/enum.rb +1 -1
  57. data/app/models/marty/event.rb +56 -59
  58. data/app/models/marty/helper.rb +38 -6
  59. data/app/models/marty/import_type.rb +6 -6
  60. data/app/models/marty/log.rb +3 -2
  61. data/app/models/marty/name_validator.rb +3 -2
  62. data/app/models/marty/pg_enum.rb +3 -4
  63. data/app/models/marty/posting.rb +20 -24
  64. data/app/models/marty/promise.rb +28 -30
  65. data/app/models/marty/script.rb +30 -28
  66. data/app/models/marty/tag.rb +8 -8
  67. data/app/models/marty/token.rb +2 -2
  68. data/app/models/marty/user.rb +24 -23
  69. data/app/models/marty/vw_promise.rb +10 -11
  70. data/config/routes.rb +2 -2
  71. data/delorean/blame_report.dl +268 -0
  72. data/{spec/dummy/delorean/fields.dl → delorean/marty_fields.dl} +8 -0
  73. data/delorean/table_report.dl +34 -0
  74. data/docker-compose.dummy.yml +2 -3
  75. data/lib/marty/aws/base.rb +8 -8
  76. data/lib/marty/aws/request.rb +4 -4
  77. data/lib/marty/cache_adapters/mcfly_ruby_cache.rb +1 -0
  78. data/lib/marty/content_handler.rb +25 -25
  79. data/lib/marty/data_change.rb +49 -71
  80. data/lib/marty/data_conversion.rb +20 -28
  81. data/lib/marty/data_exporter.rb +25 -28
  82. data/lib/marty/data_importer.rb +25 -27
  83. data/lib/marty/engine.rb +1 -2
  84. data/lib/marty/json_schema.rb +22 -24
  85. data/lib/marty/logger.rb +6 -9
  86. data/lib/marty/mcfly_model.rb +20 -24
  87. data/lib/marty/migrations.rb +37 -35
  88. data/lib/marty/monkey.rb +33 -33
  89. data/lib/marty/permissions.rb +18 -18
  90. data/lib/marty/promise_job.rb +17 -17
  91. data/lib/marty/promise_proxy.rb +6 -6
  92. data/lib/marty/relation.rb +6 -7
  93. data/lib/marty/rpc_call.rb +13 -12
  94. data/lib/marty/rule_script_set.rb +32 -28
  95. data/lib/marty/schema_helper.rb +37 -51
  96. data/lib/marty/util.rb +25 -24
  97. data/lib/marty/version.rb +1 -1
  98. data/lib/marty/xl.rb +121 -115
  99. data/make-dummy.mk +3 -0
  100. data/marty.gemspec +21 -21
  101. data/other/marty/api/base.rb +34 -35
  102. data/other/marty/diagnostic/aws/ec2_instance.rb +8 -8
  103. data/other/marty/diagnostic/base.rb +13 -14
  104. data/other/marty/diagnostic/collection.rb +2 -1
  105. data/other/marty/diagnostic/connections.rb +8 -6
  106. data/other/marty/diagnostic/database.rb +1 -0
  107. data/other/marty/diagnostic/delayed_job_version.rb +7 -9
  108. data/other/marty/diagnostic/delayed_job_worker_total_count.rb +1 -1
  109. data/other/marty/diagnostic/delayed_job_workers.rb +1 -1
  110. data/other/marty/diagnostic/environment_variables.rb +17 -15
  111. data/other/marty/diagnostic/fatal.rb +1 -1
  112. data/other/marty/diagnostic/node.rb +5 -9
  113. data/other/marty/diagnostic/nodes.rb +7 -5
  114. data/other/marty/diagnostic/packer.rb +7 -7
  115. data/other/marty/diagnostic/reporter.rb +24 -27
  116. data/other/marty/diagnostic/version.rb +3 -5
  117. data/script/rails +2 -1
  118. data/spec/controllers/application_controller_spec.rb +6 -6
  119. data/spec/controllers/delayed_job_controller_spec.rb +4 -4
  120. data/spec/controllers/diagnostic/controller_spec.rb +59 -60
  121. data/spec/controllers/job_controller_spec.rb +68 -69
  122. data/spec/controllers/rpc_controller_spec.rb +353 -359
  123. data/spec/controllers/rpc_import_spec.rb +15 -16
  124. data/spec/dummy/delorean/blame_report.dl +110 -15
  125. data/spec/dummy/delorean/data_report.dl +4 -4
  126. data/spec/dummy/delorean/marty_fields.dl +63 -0
  127. data/spec/dummy/delorean/table_report.dl +34 -0
  128. data/spec/features/auth_app_spec.rb +1 -2
  129. data/spec/features/data_import_spec.rb +2 -3
  130. data/spec/features/enum_spec.rb +42 -46
  131. data/spec/features/jobs_dashboard_spec.rb +14 -8
  132. data/spec/features/log_view_spec.rb +40 -43
  133. data/spec/features/reporting_spec.rb +15 -15
  134. data/spec/features/rule_spec.rb +195 -190
  135. data/spec/features/scripting_spec.rb +17 -20
  136. data/spec/features/scripting_test_spec.rb +32 -33
  137. data/spec/features/user_view_spec.rb +15 -17
  138. data/spec/job_helper.rb +11 -11
  139. data/spec/lib/data_blame_spec.rb +82 -0
  140. data/spec/lib/data_exporter_spec.rb +31 -32
  141. data/spec/lib/data_importer_spec.rb +382 -395
  142. data/spec/lib/delorean_query_spec.rb +117 -119
  143. data/spec/lib/json_schema_spec.rb +382 -392
  144. data/spec/lib/logger_spec.rb +23 -24
  145. data/spec/lib/mcfly_model_spec.rb +112 -109
  146. data/spec/lib/migrations_spec.rb +10 -10
  147. data/spec/lib/struct_compare_spec.rb +6 -6
  148. data/spec/lib/table_report_spec.rb +90 -0
  149. data/spec/lib/xl_spec.rb +63 -65
  150. data/spec/lib/xl_styles_spec.rb +16 -19
  151. data/spec/models/api_auth_spec.rb +30 -30
  152. data/spec/models/config_spec.rb +32 -32
  153. data/spec/models/data_grid_spec.rb +642 -655
  154. data/spec/models/event_spec.rb +96 -88
  155. data/spec/models/import_type_spec.rb +20 -20
  156. data/spec/models/posting_spec.rb +35 -35
  157. data/spec/models/promise_spec.rb +5 -5
  158. data/spec/models/rule_spec.rb +280 -269
  159. data/spec/models/script_spec.rb +27 -18
  160. data/spec/models/user_spec.rb +9 -9
  161. data/spec/other/diagnostic/base_spec.rb +20 -19
  162. data/spec/other/diagnostic/collection_spec.rb +6 -5
  163. data/spec/other/diagnostic/delayed_job_version_spec.rb +1 -1
  164. data/spec/other/diagnostic/delayed_job_workers_spec.rb +8 -8
  165. data/spec/other/diagnostic/reporter_spec.rb +31 -33
  166. data/spec/spec_helper.rb +5 -5
  167. data/spec/support/chromedriver.rb +3 -5
  168. data/spec/support/components/netzke_combobox.rb +1 -1
  169. data/spec/support/components/netzke_grid.rb +17 -17
  170. data/spec/support/custom_matchers.rb +2 -2
  171. data/spec/support/download_helper.rb +1 -1
  172. data/spec/support/helper.rb +1 -2
  173. data/spec/support/netzke.rb +31 -31
  174. data/spec/support/performance_helper.rb +8 -8
  175. data/spec/support/post_run_logger.rb +1 -2
  176. data/spec/support/setup.rb +1 -4
  177. data/spec/support/shared_connection.rb +2 -2
  178. data/spec/support/structure_compare.rb +21 -22
  179. data/spec/support/suite.rb +1 -2
  180. data/spec/support/users.rb +5 -6
  181. metadata +32 -26
@@ -1,6 +1,6 @@
1
1
  class Marty::JobController < ActionController::Base
2
2
  def download
3
- job_id = params["job_id"]
3
+ job_id = params['job_id']
4
4
 
5
5
  promise = Marty::Promise.find_by_id(job_id)
6
6
 
@@ -12,12 +12,12 @@ class Marty::JobController < ActionController::Base
12
12
 
13
13
  # somewhat hacky: if result has "result" key, it's used as the
14
14
  # content.
15
- data = data["result"] || data
15
+ data = data['result'] || data
16
16
  title = promise.title
17
17
  else
18
- format = "json"
19
- data = {error: "Job not found: #{job_id}"}
20
- title = "error"
18
+ format = 'json'
19
+ data = { error: "Job not found: #{job_id}" }
20
+ title = 'error'
21
21
  end
22
22
 
23
23
  res, type, disposition, filename =
@@ -27,6 +27,6 @@ class Marty::JobController < ActionController::Base
27
27
  type: type,
28
28
  filename: filename,
29
29
  disposition: disposition,
30
- )
30
+ )
31
31
  end
32
32
  end
@@ -3,27 +3,27 @@ class Marty::ReportController < Marty::ApplicationController
3
3
  format, req_disposition, title =
4
4
  params[:format], params[:disposition], params[:reptitle]
5
5
 
6
- raise "bad format" unless Marty::ContentHandler::GEN_FORMATS.member?(format)
6
+ raise 'bad format' unless Marty::ContentHandler::GEN_FORMATS.member?(format)
7
7
 
8
8
  data = Marty::ReportForm.run_eval(params)
9
9
 
10
10
  # hacky: shouldn't have error parsing logic here
11
- format = "json" if data.is_a?(Hash) && (data[:error] || data["error"])
11
+ format = 'json' if data.is_a?(Hash) && (data[:error] || data['error'])
12
12
 
13
13
  # hack for testing -- txt -> csv
14
- exp_format = format == "txt" ? "csv" : format
14
+ exp_format = format == 'txt' ? 'csv' : format
15
15
 
16
16
  res, type, disposition, filename =
17
- Marty::ContentHandler.
18
- export(data, exp_format, title)
17
+ Marty::ContentHandler.
18
+ export(data, exp_format, title)
19
19
 
20
20
  # hack for testing -- set content-type
21
- type = "text/plain" if format == "txt" && type =~ /csv/
21
+ type = 'text/plain' if format == 'txt' && type =~ /csv/
22
22
 
23
- return send_data(res,
24
- type: type,
25
- filename: filename,
26
- disposition: req_disposition || disposition,
27
- )
23
+ send_data(res,
24
+ type: type,
25
+ filename: filename,
26
+ disposition: req_disposition || disposition,
27
+ )
28
28
  end
29
29
  end
@@ -1,6 +1,5 @@
1
1
  class Marty::RpcController < ActionController::Base
2
2
  def evaluate
3
- begin
4
3
  # set default result and params in case of unexpected errors
5
4
  # to ensure logging capabilities
6
5
  result = nil
@@ -13,9 +12,9 @@ class Marty::RpcController < ActionController::Base
13
12
 
14
13
  # resolve api config in order to determine api class and settings
15
14
  api_config = Marty::ApiConfig.lookup(*massaged_params.values_at(
16
- :script,
17
- :node,
18
- :attr)
15
+ :script,
16
+ :node,
17
+ :attr)
19
18
  ) || {}
20
19
 
21
20
  # default to base class if no config is present
@@ -26,32 +25,32 @@ class Marty::RpcController < ActionController::Base
26
25
 
27
26
  api_params = api.process_params(massaged_params)
28
27
  auth = api.is_authorized?(api_params)
29
- return result = {error: "Permission denied"} unless auth
28
+ return result = { error: 'Permission denied' } unless auth
30
29
 
31
30
  start_time = Time.zone.now
32
31
  api.before_evaluate(api_params)
33
32
  result = api.evaluate(api_params, request, api_config)
34
33
  api.after_evaluate(api_params, result)
35
- rescue => e
34
+ rescue StandardError => e
36
35
  # log unexpected failures in rpc controller and respond with
37
36
  # generic server error
38
37
  Marty::Logger.log('rpc_controller', 'failure', e.message)
39
- result = {error: 'internal server error'}
40
- ensure
38
+ result = { error: 'internal server error' }
39
+ ensure
41
40
  # if logging is enabled, always log the result even on error
42
41
  if api_config && api_config[:logged] && api
43
42
  api.log(result,
44
- api_params + {start_time: start_time, auth: auth},
43
+ api_params + { start_time: start_time, auth: auth },
45
44
  request)
46
45
  end
47
46
 
48
47
  api.respond_to(self) do
49
- result || {'error' => 'internal server error'}
48
+ result || { 'error' => 'internal server error' }
50
49
  end
51
- end
52
50
  end
53
51
 
54
52
  private
53
+
55
54
  def process_active_params params
56
55
  # must permit params before conversion to_h
57
56
  # convert hash to json and parse to get expected hash (not indifferent)
@@ -77,7 +76,7 @@ class Marty::RpcController < ActionController::Base
77
76
  # FIXME: small patch to allow for single attr array
78
77
  attr = ActiveSupport::JSON.decode(attr) rescue attr
79
78
 
80
- return {error: "Malformed attrs"} unless
79
+ return { error: 'Malformed attrs' } unless
81
80
  attr.is_a?(String) || (attr.is_a?(Array) && attr.count == 1)
82
81
 
83
82
  # if attr is a single attr array, remember to return as an array
@@ -86,7 +85,7 @@ class Marty::RpcController < ActionController::Base
86
85
  ret_arr = true
87
86
  end
88
87
 
89
- return {error: "Malformed attrs"} unless attr =~ /\A[a-z][a-zA-Z0-9_]*\z/
88
+ return { error: 'Malformed attrs' } unless attr =~ /\A[a-z][a-zA-Z0-9_]*\z/
90
89
 
91
90
  begin
92
91
  case params
@@ -97,13 +96,13 @@ class Marty::RpcController < ActionController::Base
97
96
  when ActionController::Parameters
98
97
  params = process_active_params(params)
99
98
  else
100
- return {error: "Bad params"}
99
+ return { error: 'Bad params' }
101
100
  end
102
101
  rescue JSON::ParserError => e
103
- return {error: "Malformed params"}
102
+ return { error: 'Malformed params' }
104
103
  end
105
104
 
106
- return {error: "Malformed params"} unless params.is_a?(Hash)
105
+ return { error: 'Malformed params' } unless params.is_a?(Hash)
107
106
 
108
107
  # permit request params and convert to hash
109
108
  process_active_params(request_params.except(:rpc)).symbolize_keys + {
@@ -10,7 +10,7 @@ class Marty::ScriptSet < Delorean::AbstractContainer
10
10
 
11
11
  clear_cache
12
12
 
13
- def initialize(tag=nil)
13
+ def initialize(tag = nil)
14
14
  @tag = Marty::Tag.map_to_tag(tag)
15
15
  super()
16
16
  end
@@ -30,7 +30,7 @@ class Marty::ScriptSet < Delorean::AbstractContainer
30
30
  # hacky/rare anyway. So, don't bother for now.
31
31
 
32
32
  max_dt = Marty::Script.
33
- order("created_dt DESC").limit(1).pluck(:created_dt).first
33
+ order('created_dt DESC').limit(1).pluck(:created_dt).first
34
34
 
35
35
  @@dengines_dt ||= max_dt
36
36
 
@@ -41,7 +41,7 @@ class Marty::ScriptSet < Delorean::AbstractContainer
41
41
 
42
42
  return engine if engine
43
43
 
44
- script = Marty::Script.find_script(sname, tag) || raise("No such script")
44
+ script = Marty::Script.find_script(sname, tag) || raise('No such script')
45
45
 
46
46
  @@dengines[sname] = parse_check(sname, script.body)
47
47
  else
@@ -49,7 +49,7 @@ class Marty::ScriptSet < Delorean::AbstractContainer
49
49
 
50
50
  return engine if engine
51
51
 
52
- script = Marty::Script.find_script(sname, tag) || raise("No such script")
52
+ script = Marty::Script.find_script(sname, tag) || raise('No such script')
53
53
 
54
54
  @@engines[[tag.id, sname]] = parse_check(sname, script.body)
55
55
  end
@@ -7,10 +7,10 @@ class Marty::ApiAuth < Marty::Base
7
7
 
8
8
  class ApiAuthValidator < ActiveModel::Validator
9
9
  def validate(api)
10
- api.errors.add(:base, "API Key length must be #{KEY_SIZE*2}") if
11
- api.api_key && api.api_key.length != KEY_SIZE*2
10
+ api.errors.add(:base, "API Key length must be #{KEY_SIZE * 2}") if
11
+ api.api_key && api.api_key.length != KEY_SIZE * 2
12
12
 
13
- api.errors.add(:base, "Script Name must reference a valid script") unless
13
+ api.errors.add(:base, 'Script Name must reference a valid script') unless
14
14
  Marty::Script.find_script(api.script_name, nil)
15
15
  end
16
16
  end
@@ -21,10 +21,9 @@ class Marty::ApiAuth < Marty::Base
21
21
  validates_uniqueness_of :app_name, scope: [:script_name,
22
22
  :obsoleted_dt]
23
23
 
24
-
25
24
  before_validation do
26
25
  self.api_key = Marty::ApiAuth.generate_key if
27
- self.api_key.blank?
26
+ api_key.blank?
28
27
  end
29
28
 
30
29
  def self.generate_key
@@ -17,6 +17,6 @@ class Marty::ApiConfig < Marty::Base
17
17
 
18
18
  def self.multi_lookup(script, node, attrs)
19
19
  (attrs.nil? ? [nil] : attrs).
20
- map { |attr| lookup(script, node, attr).try{|x| x.unshift(attr) }}
20
+ map { |attr| lookup(script, node, attr).try { |x| x.unshift(attr) } }
21
21
  end
22
22
  end
@@ -1,10 +1,10 @@
1
1
  class Marty::Base < ActiveRecord::Base
2
- self.table_name_prefix = "marty_"
2
+ self.table_name_prefix = 'marty_'
3
3
  self.abstract_class = true
4
4
 
5
5
  def self.mcfly_pt(pt)
6
- tb = self.table_name
7
- self.where("#{tb}.obsoleted_dt >= ? AND #{tb}.created_dt < ?", pt, pt)
6
+ tb = table_name
7
+ where("#{tb}.obsoleted_dt >= ? AND #{tb}.created_dt < ?", pt, pt)
8
8
  end
9
9
 
10
10
  class << self
@@ -13,9 +13,9 @@ class Marty::Base < ActiveRecord::Base
13
13
 
14
14
  def self.get_struct_attrs
15
15
  self.struct_attrs ||=
16
- self.attribute_names - Mcfly::COLUMNS.to_a -
17
- (self.const_defined?('MCFLY_UNIQUENESS') &&
18
- self.const_get('MCFLY_UNIQUENESS') || []).map(&:to_s)
16
+ attribute_names - Mcfly::COLUMNS.to_a -
17
+ (const_defined?('MCFLY_UNIQUENESS') &&
18
+ const_get('MCFLY_UNIQUENESS') || []).map(&:to_s)
19
19
  end
20
20
 
21
21
  def self.get_final_attrs
@@ -48,12 +48,13 @@ class Marty::Base < ActiveRecord::Base
48
48
 
49
49
  def self.make_openstruct(inst)
50
50
  return nil unless inst
51
+
51
52
  fa = get_final_attrs
52
53
  os = OpenStruct.new(inst.attributes.slice(*fa))
53
54
  if self == Marty::DataGrid
54
55
  def os.lookup_grid_distinct_entry(pt, params)
55
- dgh = self.to_h.stringify_keys.slice(
56
- "id", "group_id", "created_dt", "metadata", "data_type")
56
+ dgh = to_h.stringify_keys.slice(
57
+ 'id', 'group_id', 'created_dt', 'metadata', 'data_type')
57
58
  Marty::DataGrid.lookup_grid_distinct_entry_h(pt, params, dgh)
58
59
  end
59
60
  end
@@ -9,6 +9,7 @@ class Marty::BaseRule < Marty::Base
9
9
  def chkrange(v)
10
10
  v.match(/\A(\[|\()([0-9\.-]*),([0-9\.-]*)(\]|\))\z/)
11
11
  end
12
+
12
13
  def gettypes(v)
13
14
  types = []
14
15
  types << :string if v.is_a?(String)
@@ -20,6 +21,7 @@ class Marty::BaseRule < Marty::Base
20
21
  types << :boolean if [true, false, 'True', 'False'].include?(v)
21
22
  types
22
23
  end
24
+
23
25
  def check(name, h)
24
26
  multi, type, enum, values, req = h.values_at(:multi, :type, :enum, :values,
25
27
  :required)
@@ -31,6 +33,7 @@ class Marty::BaseRule < Marty::Base
31
33
  return errors[errtype] << "- Required field #{ns} is missing" if
32
34
  v.blank? && req
33
35
  return if v.blank?
36
+
34
37
  gotmulti = v.is_a?(Array) ? 'multi' : 'single'
35
38
  return errors[errtype] << "- Wrong arity for #{ns} (expected #{expmulti} "\
36
39
  "got #{gotmulti})" if expmulti != gotmulti
@@ -40,22 +43,24 @@ class Marty::BaseRule < Marty::Base
40
43
  gettypes(vv).member?(type)
41
44
  end
42
45
  return unless enum || values
46
+
43
47
  vals = enum && enum::VALUES || values.to_set
44
48
  bad = (vs - vals)
45
49
  p = bad.count > 1 ? 's' : ''
46
50
  return errors[errtype] <<
47
51
  %Q(- Bad value#{p} '#{bad.to_a.join("', '")}' for #{ns}) if bad.present?
48
52
  end
53
+
49
54
  def validate
50
55
  self.class.guard_info.each { |name, h| check(name, h) }
51
56
  grids.each do |vn, gn|
52
57
  return errors[:grids] << "- Bad grid name '#{gn}' for '#{vn}'" unless
53
58
  gn.blank? || Marty::DataGrid.lookup('infinity', gn)
54
59
  end
55
- cg_err = computed_guards.delete("~~ERROR~~")
60
+ cg_err = computed_guards.delete('~~ERROR~~')
56
61
  errors[:computed] <<
57
62
  "- Error in rule '#{name}' field 'computed_guards': #{cg_err.capitalize}" if cg_err
58
- res_err = results.delete("~~ERROR~~")
63
+ res_err = results.delete('~~ERROR~~')
59
64
  errors[:computed] <<
60
65
  "- Error in rule '#{name}' field 'results': #{res_err.capitalize}" if res_err
61
66
  end
@@ -71,45 +76,45 @@ class Marty::BaseRule < Marty::Base
71
76
  end
72
77
 
73
78
  before_create do
74
- self.class.guard_info.each do |k,v|
79
+ self.class.guard_info.each do |k, v|
75
80
  next if !v.include?(:default) || self.simple_guards.include?(k)
81
+
76
82
  self.simple_guards[k] = v[:default]
77
83
  end
78
84
  end
79
85
 
80
86
  def self.get_subq(field, subfield, multi, type, vraw)
81
87
  arrow = multi || ![:range, :string, :date, :datetime].include?(type) ?
82
- "->" : "->>"
83
- op = multi || type == :range ? "@>" : "="
88
+ '->' : '->>'
89
+ op = multi || type == :range ? '@>' : '='
84
90
  value0 = [:string, :date, :datetime].include?(type) ?
85
91
  ActiveRecord::Base.connection.quote(vraw) :
86
92
  type == :range ? vraw.to_f :
87
93
  "'#{vraw}'::jsonb"
88
94
  value = multi ? %Q('["%s"]') % value0[1..-2] : value0
89
- fieldcast = type == :range ? "::numrange" : ''
95
+ fieldcast = type == :range ? '::numrange' : ''
90
96
  "(#{field}#{arrow}'#{subfield}')#{fieldcast} #{op} #{value}"
91
97
  end
92
98
 
93
99
  def self.get_matches_(pt, attrs, params)
94
-
95
- q = select("DISTINCT ON (name) *").where(attrs)
100
+ q = select('DISTINCT ON (name) *').where(attrs)
96
101
 
97
102
  params.each do |k, vraw|
98
103
  h = guard_info
99
104
  use_k = (h[k] && k) ||
100
- (h[k+"_array"] && k+"_array") ||
101
- (h[k+"_range"] && k+"_range")
105
+ (h[k + '_array'] && k + '_array') ||
106
+ (h[k + '_range'] && k + '_range')
102
107
  next unless use_k
108
+
103
109
  multi, type = h[use_k].values_at(:multi, :type)
104
110
  filts = [vraw].flatten.map do |v|
105
111
  qstr = get_subq('simple_guards', use_k, multi, type, v)
106
- end.join(" OR ")
112
+ end.join(' OR ')
107
113
  isn = "simple_guards->'#{use_k}' IS NULL OR"
108
114
 
109
115
  q = q.where("(#{isn} #{filts})")
110
116
  end
111
- #print q.to_sql
117
+ # print q.to_sql
112
118
  q.order(:name)
113
119
  end
114
-
115
120
  end
@@ -2,7 +2,7 @@ class Marty::Config < Marty::Base
2
2
  class ConfigValidator < ActiveModel::Validator
3
3
  def validate(entry)
4
4
  v = entry.get_value
5
- entry.errors[:base] << "bad JSON value" if v.nil?
5
+ entry.errors[:base] << 'bad JSON value' if v.nil?
6
6
  v
7
7
  end
8
8
  end
@@ -11,13 +11,12 @@ class Marty::Config < Marty::Base
11
11
  validates_uniqueness_of :key
12
12
  validates_with ConfigValidator
13
13
 
14
- delorean_fn :lookup, sig: 1 do
15
- |key|
14
+ delorean_fn :lookup, sig: 1 do |key|
16
15
  self[key]
17
16
  end
18
17
 
19
18
  def get_value
20
- self.value[0]
19
+ value[0]
21
20
  end
22
21
 
23
22
  def set_value(v)
@@ -27,7 +26,7 @@ class Marty::Config < Marty::Base
27
26
  def self.[]=(key, value)
28
27
  entry = find_by_key(key)
29
28
  if !entry
30
- entry = self.new
29
+ entry = new
31
30
  entry.key = key
32
31
  end
33
32
  entry.set_value(value)
@@ -1,40 +1,37 @@
1
1
  class Marty::DataGrid < Marty::Base
2
2
  # If data_type is nil, assume float
3
- DEFAULT_DATA_TYPE = "float"
3
+ DEFAULT_DATA_TYPE = 'float'
4
4
 
5
5
  INDEX_MAP = {
6
- "numrange" => Marty::GridIndexNumrange,
7
- "int4range" => Marty::GridIndexInt4range,
8
- "integer" => Marty::GridIndexInteger,
9
- "string" => Marty::GridIndexString,
10
- "boolean" => Marty::GridIndexBoolean,
6
+ 'numrange' => Marty::GridIndexNumrange,
7
+ 'int4range' => Marty::GridIndexInt4range,
8
+ 'integer' => Marty::GridIndexInteger,
9
+ 'string' => Marty::GridIndexString,
10
+ 'boolean' => Marty::GridIndexBoolean,
11
11
  }
12
12
 
13
13
  ARRSEP = '|'
14
14
 
15
15
  class DataGridValidator < ActiveModel::Validator
16
16
  def validate(dg)
17
-
18
17
  dg.errors.add(:base, "'#{dg.data_type}' not a defined type or class") unless
19
18
  Marty::DataGrid.convert_data_type(dg.data_type)
20
19
 
21
- dg.errors.add(:base, "data must be array of arrays") unless
22
- dg.data.is_a?(Array) && dg.data.all? {|a| a.is_a? Array}
23
-
24
- dg.errors.add(:base, "metadata must be an array of hashes") unless
25
- dg.metadata.is_a?(Array) && dg.metadata.all? {|a| a.is_a? Hash}
20
+ dg.errors.add(:base, 'data must be array of arrays') unless
21
+ dg.data.is_a?(Array) && dg.data.all? { |a| a.is_a? Array }
26
22
 
27
- dg.errors.add(:base, "metadata must contain only h/v dirs") unless
28
- dg.metadata.all? {|h| ["h", "v"].member? h["dir"]}
23
+ dg.errors.add(:base, 'metadata must be an array of hashes') unless
24
+ dg.metadata.is_a?(Array) && dg.metadata.all? { |a| a.is_a? Hash }
29
25
 
30
- dg.errors.add(:base, "metadata item attrs must be unique") unless
31
- dg.metadata.map {|h| h["attr"]}.uniq.length == dg.metadata.length
26
+ dg.errors.add(:base, 'metadata must contain only h/v dirs') unless
27
+ dg.metadata.all? { |h| ['h', 'v'].member? h['dir'] }
32
28
 
33
- dg.metadata.each do
34
- |inf|
29
+ dg.errors.add(:base, 'metadata item attrs must be unique') unless
30
+ dg.metadata.map { |h| h['attr'] }.uniq.length == dg.metadata.length
35
31
 
32
+ dg.metadata.each do |inf|
36
33
  attr, type, keys, rs_keep =
37
- inf["attr"], inf["type"], inf["keys"], inf["rs_keep"]
34
+ inf['attr'], inf['type'], inf['keys'], inf['rs_keep']
38
35
 
39
36
  unless rs_keep.nil? || rs_keep.empty?
40
37
  m = /\A *(<|<=|>|>=)? *([a-z][a-z_0-9]+) *\z/.match(rs_keep)
@@ -44,7 +41,7 @@ class Marty::DataGrid < Marty::Base
44
41
  end
45
42
  end
46
43
 
47
- dg.errors.add(:base, "metadata elements must have attr/type/keys") unless
44
+ dg.errors.add(:base, 'metadata elements must have attr/type/keys') unless
48
45
  attr && type && keys
49
46
 
50
47
  # enforce Delorean attr syntax (a bit Draconian)
@@ -54,24 +51,24 @@ class Marty::DataGrid < Marty::Base
54
51
  dg.errors.add(:base, "unknown metadata type #{type}") unless
55
52
  Marty::DataGrid.type_to_index(type)
56
53
 
57
- dg.errors.add(:base, "bad metadata keys") unless
58
- keys.is_a?(Array) && keys.length>0
54
+ dg.errors.add(:base, 'bad metadata keys') unless
55
+ keys.is_a?(Array) && !keys.empty?
59
56
  end
60
57
 
61
58
  # Check key uniqueness of vertical/horizontal key
62
59
  # combinations. FIXME: ideally, we should also check for
63
60
  # array/range key subsumption. Those will result in runtime
64
61
  # errors anyway when multiple hits are produced.
65
- v_keys = dg.dir_infos("v").map {|inf| inf["keys"]}
66
- h_keys = dg.dir_infos("h").map {|inf| inf["keys"]}
62
+ v_keys = dg.dir_infos('v').map { |inf| inf['keys'] }
63
+ h_keys = dg.dir_infos('h').map { |inf| inf['keys'] }
67
64
 
68
65
  v_zip_keys = v_keys.empty? ? [] : v_keys[0].zip(*v_keys[1..-1])
69
66
  h_zip_keys = h_keys.empty? ? [] : h_keys[0].zip(*h_keys[1..-1])
70
67
 
71
- dg.errors.add(:base, "duplicate horiz. key combination") unless
68
+ dg.errors.add(:base, 'duplicate horiz. key combination') unless
72
69
  h_zip_keys.uniq.length == h_zip_keys.length
73
70
 
74
- dg.errors.add(:base, "duplicate vertical key combination") unless
71
+ dg.errors.add(:base, 'duplicate vertical key combination') unless
75
72
  v_zip_keys.uniq.length == v_zip_keys.length
76
73
  end
77
74
  end
@@ -89,26 +86,23 @@ class Marty::DataGrid < Marty::Base
89
86
 
90
87
  # FIXME: if the caller requests data as part of fields, there could
91
88
  # be memory concerns with caching since some data_grids have massive data
92
- cached_delorean_fn :lookup_h, sig: [2, 3] do
93
- |pt, name, fields = nil|
89
+ cached_delorean_fn :lookup_h, sig: [2, 3] do |pt, name, fields = nil|
94
90
  fields ||= %w(id group_id created_dt metadata data_type name)
95
91
  dga = mcfly_pt(pt).where(name: name).pluck(*fields).first
96
92
  dga && Hash[fields.zip(dga)]
97
93
  end
98
94
 
99
95
  # deprecated - remove 2018-Oct
100
- cached_mcfly_lookup :lookup_id, sig: 2 do
101
- |pt, group_id|
96
+ cached_mcfly_lookup :lookup_id, sig: 2 do |pt, group_id|
102
97
  find_by_group_id group_id
103
98
  end
104
99
 
105
- cached_delorean_fn :exists, sig: 2 do
106
- |pt, name|
100
+ cached_delorean_fn :exists, sig: 2 do |pt, name|
107
101
  Marty::DataGrid.mcfly_pt(pt).where(name: name).exists?
108
102
  end
109
103
 
110
104
  def self.get_struct_attrs
111
- self.struct_attrs ||= super + ["id", "group_id", "created_dt", "name"]
105
+ self.struct_attrs ||= super + ['id', 'group_id', 'created_dt', 'name']
112
106
  end
113
107
 
114
108
  def to_s
@@ -125,6 +119,7 @@ class Marty::DataGrid < Marty::Base
125
119
  def self.register_rule_handler(handler)
126
120
  (@@rule_handlers ||= []) << handler
127
121
  end
122
+
128
123
  def update_rules(old, new)
129
124
  @@rule_handlers.each { |rh| rh.call(old, new) }
130
125
  end
@@ -133,7 +128,7 @@ class Marty::DataGrid < Marty::Base
133
128
  # transaction -- i.e. together with build_index. before_save would
134
129
  # be OK, but then save inside it would cause an infinite loop.
135
130
  def save!
136
- if self.changed?
131
+ if changed?
137
132
  transaction do
138
133
  nc, nw, n = [name_changed?, name_was, name]
139
134
  res = super
@@ -147,14 +142,15 @@ class Marty::DataGrid < Marty::Base
147
142
 
148
143
  # FIXME: hacky -- save is just save!
149
144
  def save
150
- self.save!
145
+ save!
151
146
  end
152
147
 
153
148
  def self.type_to_index(type)
154
149
  # map given header type to an index class -- uses string index
155
150
  # for ruby classes.
156
151
  return INDEX_MAP[type] if INDEX_MAP[type]
157
- INDEX_MAP["string"] if (type.constantize rescue nil)
152
+
153
+ INDEX_MAP['string'] if (type.constantize rescue nil)
158
154
  end
159
155
 
160
156
  def self.convert_data_type(data_type)
@@ -172,29 +168,30 @@ class Marty::DataGrid < Marty::Base
172
168
  @@dtcache = {}
173
169
  end
174
170
 
175
- PLV_DT_FMT = "%Y-%m-%d %H:%M:%S.%N6"
171
+ PLV_DT_FMT = '%Y-%m-%d %H:%M:%S.%N6'
176
172
 
177
- def self.plv_lookup_grid_distinct(h_passed, dgh, ret_grid_data=false,
178
- distinct=true)
179
- cd = dgh["created_dt"]
173
+ def self.plv_lookup_grid_distinct(h_passed, dgh, ret_grid_data = false,
174
+ distinct = true)
175
+ cd = dgh['created_dt']
180
176
  @@dtcache ||= {}
181
177
  @@dtcache[cd] ||= cd.strftime(PLV_DT_FMT)
182
178
  row_info = {
183
- "id" => dgh["id"],
184
- "group_id" => dgh["group_id"],
185
- "created_dt" => @@dtcache[cd]
179
+ 'id' => dgh['id'],
180
+ 'group_id' => dgh['group_id'],
181
+ 'created_dt' => @@dtcache[cd]
186
182
  }
187
183
 
188
- h = dgh["metadata"].each_with_object({}) do |m, h|
189
- attr = m["attr"]
184
+ h = dgh['metadata'].each_with_object({}) do |m, h|
185
+ attr = m['attr']
190
186
  inc = h_passed.fetch(attr, :__nf__)
191
187
  next if inc == :__nf__
188
+
192
189
  val = (defined? inc.name) ? inc.name : inc
193
190
  h[attr] = val.is_a?(String) ?
194
191
  ActiveRecord::Base.connection.quote(val)[1..-2] : val
195
192
  end
196
193
 
197
- fn = "lookup_grid_distinct"
194
+ fn = 'lookup_grid_distinct'
198
195
  hjson = "'#{h.to_json}'::JSONB"
199
196
  rijson = "'#{row_info.to_json}'::JSONB"
200
197
  params = "#{hjson}, #{rijson}, #{ret_grid_data}, #{distinct}"
@@ -202,66 +199,63 @@ class Marty::DataGrid < Marty::Base
202
199
  raw = ActiveRecord::Base.connection.execute(sql)[0][fn]
203
200
  res = JSON.parse(raw)
204
201
 
205
- if res["error"]
206
- msg = res["error"]
207
- parms, sqls, ress, dg = res["error_extra"].values_at(
208
- "params", "sql", "results", "dg")
202
+ if res['error']
203
+ msg = res['error']
204
+ parms, sqls, ress, dg = res['error_extra'].values_at(
205
+ 'params', 'sql', 'results', 'dg')
209
206
 
210
207
  raise "DG #{name}: Error in PLV8 call: #{msg}\n"\
211
208
  "params: #{parms}\n"\
212
209
  "sqls: #{sqls}\n"\
213
210
  "results: #{ress}\n"\
214
211
  "dg: #{dg}\n"\
215
- "ri: #{row_info}" if res["error"]
212
+ "ri: #{row_info}" if res['error']
216
213
  end
217
214
 
218
215
  if ret_grid_data
219
- dg = find(dgh["id"])
216
+ dg = find(dgh['id'])
220
217
  md, mmd = modify_grid(h_passed, dg.metadata, dg.data)
221
- res["data"] = md
222
- res["metadata"] = mmd
218
+ res['data'] = md
219
+ res['metadata'] = mmd
223
220
  end
224
221
  res
225
222
  end
226
223
 
227
224
  # deprecated - remove 2018-Oct
228
- cached_delorean_fn :lookup_grid, sig: 4 do
229
- |pt, dg, h, distinct|
225
+ cached_delorean_fn :lookup_grid, sig: 4 do |pt, dg, h, distinct|
230
226
  dg_is_grid = Marty::DataGrid === dg
231
- dg_is_os = dg.is_a?(OpenStruct)
227
+ dg_is_os = dg.is_a?(OpenStruct)
232
228
  raise "bad DataGrid #{dg}" unless dg_is_grid || dg_is_os
233
229
  raise "non-hash arg #{h}" unless Hash === h
230
+
234
231
  dgh = dg_is_os ? dg.to_h.stringify_keys :
235
232
  dg.attributes.slice('id', 'group_id', 'created_dt', 'metadata')
236
233
  res = plv_lookup_grid_distinct(h, dgh, false, distinct)
237
- res["result"]
234
+ res['result']
238
235
  end
239
236
 
240
- cached_delorean_fn :lookup_grid_h, sig: 4 do
241
- |pt, dgn, h, distinct|
242
-
237
+ cached_delorean_fn :lookup_grid_h, sig: 4 do |pt, dgn, h, distinct|
243
238
  dgh = lookup_h(pt, dgn)
244
239
  raise "#{dgn} grid not found" unless dgh
245
240
  raise "non-hash arg #{h}" unless Hash === h
246
241
 
247
242
  res = lookup_grid_distinct_entry_h(pt, h, dgh, nil, true, false, distinct)
248
- res["result"]
243
+ res['result']
249
244
  end
250
245
 
251
246
  # FIXME: using cached_delorean_fn just for the caching -- this is
252
247
  # not expected to be called from Delorean.
253
- cached_delorean_fn :find_class_instance, sig: 3 do
254
- |pt, klass, v|
248
+ cached_delorean_fn :find_class_instance, sig: 3 do |pt, klass, v|
255
249
  if Marty::PgEnum === klass
256
250
  klass.find_by_name(v)
257
251
  else
258
252
  # FIXME: very hacky -- hard-coded name
259
- Marty::DataConversion.find_row(klass, {"name" => v}, pt)
253
+ Marty::DataConversion.find_row(klass, { 'name' => v }, pt)
260
254
  end
261
255
  end
262
256
 
263
- def self.lookup_grid_distinct_entry_h(pt, h, dgh, visited=nil, follow=true,
264
- return_grid_data=false, distinct=true)
257
+ def self.lookup_grid_distinct_entry_h(pt, h, dgh, visited = nil, follow = true,
258
+ return_grid_data = false, distinct = true)
265
259
 
266
260
  # Perform grid lookup, if result is another data_grid, and follow is true,
267
261
  # then perform lookup on the resulting grid. Allows grids to be nested
@@ -275,15 +269,15 @@ class Marty::DataGrid < Marty::Base
275
269
  # "metadata" => <grid's metadata (array of hashes)>
276
270
  vhash = plv_lookup_grid_distinct(h, dgh, return_grid_data, distinct)
277
271
 
278
- return vhash if vhash["result"].nil? || !dgh['data_type']
272
+ return vhash if vhash['result'].nil? || !dgh['data_type']
279
273
 
280
274
  c_data_type = Marty::DataGrid.convert_data_type(dgh['data_type'])
281
275
 
282
276
  return vhash if String === c_data_type
283
277
 
284
- res = vhash["result"]
278
+ res = vhash['result']
285
279
 
286
- v = case
280
+ v = case
287
281
  when Marty::PgEnum === res
288
282
  c_data_type.find_by_name(res)
289
283
  when Marty::DataGrid == c_data_type
@@ -291,10 +285,10 @@ class Marty::DataGrid < Marty::Base
291
285
  Marty::DataGrid.lookup_h(pt, res) :
292
286
  Marty::DataGrid.lookup(pt, res)
293
287
  else
294
- Marty::DataConversion.find_row(c_data_type, {"name" => res}, pt)
288
+ Marty::DataConversion.find_row(c_data_type, { 'name' => res }, pt)
295
289
  end
296
290
 
297
- return vhash.merge({"result" => v}) unless (Marty::DataGrid == c_data_type &&
291
+ return vhash.merge('result' => v) unless (Marty::DataGrid == c_data_type &&
298
292
  follow)
299
293
 
300
294
  visited ||= []
@@ -309,24 +303,22 @@ class Marty::DataGrid < Marty::Base
309
303
  end
310
304
 
311
305
  def dir_infos(dir)
312
- metadata.select {|inf| inf["dir"] == dir}
306
+ metadata.select { |inf| inf['dir'] == dir }
313
307
  end
314
308
 
315
309
  def self.export_keys(inf)
316
310
  # should unify this with Marty::DataConversion.convert
317
311
 
318
- type = inf["type"]
312
+ type = inf['type']
319
313
  klass = type.constantize unless INDEX_MAP[type]
320
314
 
321
- inf["keys"].map do
322
- |v|
323
-
315
+ inf['keys'].map do |v|
324
316
  case type
325
- when "numrange", "int4range"
317
+ when 'numrange', 'int4range'
326
318
  Marty::Util.pg_range_to_human(v)
327
- when "boolean"
319
+ when 'boolean'
328
320
  v.to_s
329
- when "string", "integer"
321
+ when 'string', 'integer'
330
322
  v.map(&:to_s).join(ARRSEP) if v
331
323
  else
332
324
  # assume it's an AR class
@@ -350,46 +342,45 @@ class Marty::DataGrid < Marty::Base
350
342
 
351
343
  def export_array
352
344
  # add data type metadata row if not default
353
- dt_row = lenient ? ["lenient"] : []
345
+ dt_row = lenient ? ['lenient'] : []
354
346
  dt_row << data_type unless [nil, DEFAULT_DATA_TYPE].member?(data_type)
355
347
 
356
348
  meta_rows = dt_row.empty? ? [] : [[dt_row.join(' ')]]
357
349
 
358
- meta_rows += metadata.map { |inf|
359
- [inf["attr"], inf["type"], inf["dir"], inf["rs_keep"] || ""]
360
- }
350
+ meta_rows += metadata.map do |inf|
351
+ [inf['attr'], inf['type'], inf['dir'], inf['rs_keep'] || '']
352
+ end
361
353
 
362
- v_infos, h_infos = dir_infos("v"), dir_infos("h")
354
+ v_infos, h_infos = dir_infos('v'), dir_infos('h')
363
355
 
364
- h_key_rows = h_infos.map { |inf|
365
- [nil]*v_infos.count + self.class.export_keys(inf)
366
- }
356
+ h_key_rows = h_infos.map do |inf|
357
+ [nil] * v_infos.count + self.class.export_keys(inf)
358
+ end
367
359
 
368
360
  transposed_v_keys = v_infos.empty? ? [[]] :
369
- v_infos.map {|inf| self.class.export_keys(inf)}.transpose
361
+ v_infos.map { |inf| self.class.export_keys(inf) }.transpose
370
362
 
371
- data_rows = transposed_v_keys.each_with_index.map { |keys, i|
372
- keys + (self.data[i] || [])
373
- }
363
+ data_rows = transposed_v_keys.each_with_index.map do |keys, i|
364
+ keys + (data[i] || [])
365
+ end
374
366
 
375
367
  [meta_rows, h_key_rows, data_rows]
376
368
  end
377
369
 
378
370
  def export
379
- # return null string when called from Netzke on add_in_form
380
- return "" if metadata.nil? && data.nil?
371
+ # return null string when called from Netzke on add_in_form
372
+ return '' if metadata.nil? && data.nil?
381
373
 
382
- meta_rows, h_key_rows, data_rows = export_array
374
+ meta_rows, h_key_rows, data_rows = export_array
383
375
 
384
- Marty::DataExporter.
385
- to_csv(meta_rows + [[]] + h_key_rows + data_rows,
386
- "col_sep" => "\t",
376
+ Marty::DataExporter.
377
+ to_csv(meta_rows + [[]] + h_key_rows + data_rows,
378
+ 'col_sep' => "\t",
387
379
  ).
388
- gsub(/\"\"/, '') # remove "" to beautify output
380
+ gsub(/\"\"/, '') # remove "" to beautify output
389
381
  end
390
382
 
391
- delorean_fn :export, sig: 1 do
392
- |os|
383
+ delorean_fn :export, sig: 1 do |os|
393
384
  dg = find(os.id)
394
385
  dg.export
395
386
  end
@@ -398,27 +389,28 @@ class Marty::DataGrid < Marty::Base
398
389
  return unless v
399
390
 
400
391
  case type
401
- when "numrange", "int4range"
392
+ when 'numrange', 'int4range'
402
393
  Marty::Util.human_to_pg_range(v)
403
- when "integer"
394
+ when 'integer'
404
395
  v.split(ARRSEP).map do |val|
405
396
  Integer(val) rescue raise "invalid integer: #{val}"
406
397
  end.uniq.sort
407
- when "float"
398
+ when 'float'
408
399
  v.split(ARRSEP).map do |val|
409
400
  Float(val) rescue raise "invalid float: #{val}"
410
401
  end.uniq.sort
411
- when "string"
402
+ when 'string'
412
403
  res = v.split(ARRSEP).uniq.sort
413
- raise "leading/trailing spaces in elements not allowed" if
414
- res.any? {|x| x != x.strip}
415
- raise "0-length string not allowed" if res.any?(&:empty?)
404
+ raise 'leading/trailing spaces in elements not allowed' if
405
+ res.any? { |x| x != x.strip }
406
+ raise '0-length string not allowed' if res.any?(&:empty?)
407
+
416
408
  res
417
- when "boolean"
409
+ when 'boolean'
418
410
  case v.downcase
419
- when "true", "t"
411
+ when 'true', 't'
420
412
  true
421
- when "false", "f"
413
+ when 'false', 'f'
422
414
  false
423
415
  else
424
416
  raise "bad boolean #{v}"
@@ -427,8 +419,7 @@ class Marty::DataGrid < Marty::Base
427
419
  # AR class
428
420
  # FIXME: won't work if the obj identifier (name) has ARRSEP
429
421
  res = v.split(ARRSEP).uniq
430
- res.each do
431
- |k|
422
+ res.each do |k|
432
423
  begin
433
424
  # check to see if class instance actually exists
434
425
  Marty::DataGrid.
@@ -442,17 +433,14 @@ class Marty::DataGrid < Marty::Base
442
433
  end
443
434
 
444
435
  def self.maybe_get_klass(type)
445
- begin
446
- type.constantize unless INDEX_MAP[type] || type == "float"
447
- rescue NameError
436
+ type.constantize unless INDEX_MAP[type] || type == 'float'
437
+ rescue NameError
448
438
  raise "unknown header type/klass: #{type}"
449
- end
450
439
  end
451
440
 
452
441
  def self.parse_keys(pt, keys, type)
453
442
  klass = maybe_get_klass(type)
454
- keys.map do
455
- |v|
443
+ keys.map do |v|
456
444
  parse_fvalue(pt, v, type, klass)
457
445
  end
458
446
  end
@@ -465,9 +453,9 @@ class Marty::DataGrid < Marty::Base
465
453
  pt ||= 'infinity'
466
454
 
467
455
  rows = CSV.new(grid_text, options).to_a
468
- blank_index = rows.find_index {|x| x.all?(&:nil?)}
456
+ blank_index = rows.find_index { |x| x.all?(&:nil?) }
469
457
 
470
- raise "must have a blank row separating metadata" unless
458
+ raise 'must have a blank row separating metadata' unless
471
459
  blank_index
472
460
 
473
461
  raise "can't import grid with trailing blank column" if
@@ -483,61 +471,58 @@ class Marty::DataGrid < Marty::Base
483
471
  dts = dt.split
484
472
  raise "bad data type '#{dt}'" if dts.count > 2
485
473
 
486
- lenient = dts.delete "lenient"
474
+ lenient = dts.delete 'lenient'
487
475
  data_type = dts.first
488
476
  end
489
477
 
490
- metadata = rows[(data_type || lenient ? 1 : 0)...blank_index].map do
491
- |attr, type, dir, rs_keep, key|
492
-
493
- raise "metadata elements must include attr/type/dir" unless
478
+ rows_for_metadata = rows[(data_type || lenient ? 1 : 0)...blank_index]
479
+ metadata = rows_for_metadata.map do |attr, type, dir, rs_keep, key|
480
+ raise 'metadata elements must include attr/type/dir' unless
494
481
  attr && type && dir
495
- raise "bad dir #{dir}" unless ["h", "v"].member? dir
482
+ raise "bad dir #{dir}" unless ['h', 'v'].member? dir
496
483
  raise "unknown metadata type #{type}" unless
497
484
  Marty::DataGrid.type_to_index(type)
498
485
 
499
486
  res = {
500
- "attr" => attr,
501
- "type" => type,
502
- "dir" => dir,
503
- "keys" => key && parse_keys(pt, [key], type),
487
+ 'attr' => attr,
488
+ 'type' => type,
489
+ 'dir' => dir,
490
+ 'keys' => key && parse_keys(pt, [key], type),
504
491
  }
505
- res["rs_keep"] = rs_keep if rs_keep
492
+ res['rs_keep'] = rs_keep if rs_keep
506
493
  res
507
494
  end
508
495
 
509
- v_infos = metadata.select {|inf| inf["dir"] == "v"}
510
- h_infos = metadata.select {|inf| inf["dir"] == "h"}
496
+ v_infos = metadata.select { |inf| inf['dir'] == 'v' }
497
+ h_infos = metadata.select { |inf| inf['dir'] == 'h' }
511
498
 
512
499
  # keys+data start right after blank_index
513
- data_index = blank_index+1
500
+ data_index = blank_index + 1
514
501
 
515
502
  # process horizontal key rows
516
- h_infos.each_with_index do
517
- |inf, i|
503
+ h_infos.each_with_index do |inf, i|
504
+ row = rows[data_index + i]
518
505
 
519
- row = rows[data_index+i]
520
-
521
- raise "horiz. key row #{data_index+i} must include nil starting cells" if
506
+ raise "horiz. key row #{data_index + i} must include nil starting cells" if
522
507
  row[0, v_infos.count].any?
523
508
 
524
- inf["keys"] = parse_keys(pt, row[v_infos.count, row.count], inf["type"])
509
+ inf['keys'] = parse_keys(pt, row[v_infos.count, row.count], inf['type'])
525
510
  end
526
511
 
527
- raise "horiz. info keys length mismatch!" unless
528
- h_infos.map {|inf| inf["keys"].length}.uniq.count <= 1
512
+ raise 'horiz. info keys length mismatch!' unless
513
+ h_infos.map { |inf| inf['keys'].length }.uniq.count <= 1
529
514
 
530
- data_rows = rows[data_index+h_infos.count, rows.count]
515
+ data_rows = rows[data_index + h_infos.count, rows.count]
531
516
 
532
517
  # process vertical key columns
533
- v_key_cols = data_rows.map {|r| r[0, v_infos.count]}.transpose
518
+ v_key_cols = data_rows.map { |r| r[0, v_infos.count] }.transpose
534
519
 
535
520
  v_infos.each_with_index do |inf, i|
536
- inf["keys"] = parse_keys(pt, v_key_cols[i], inf["type"])
521
+ inf['keys'] = parse_keys(pt, v_key_cols[i], inf['type'])
537
522
  end
538
523
 
539
- raise "vert. info keys length mismatch!" unless
540
- v_infos.map {|inf| inf["keys"].length}.uniq.count <= 1
524
+ raise 'vert. info keys length mismatch!' unless
525
+ v_infos.map { |inf| inf['keys'].length }.uniq.count <= 1
541
526
 
542
527
  c_data_type = Marty::DataGrid.convert_data_type(data_type)
543
528
 
@@ -548,18 +533,14 @@ class Marty::DataGrid < Marty::Base
548
533
  if String === c_data_type
549
534
  tsym = c_data_type.to_sym
550
535
 
551
- data = data_rows.map do
552
- |r|
553
- r[v_infos.count, r.count].map do
554
- |v|
536
+ data = data_rows.map do |r|
537
+ r[v_infos.count, r.count].map do |v|
555
538
  Marty::DataConversion.convert(v, tsym) if v
556
539
  end
557
540
  end
558
541
  else
559
- data = data_rows.map do
560
- |r|
561
- r[v_infos.count, r.count].map do
562
- |v|
542
+ data = data_rows.map do |r|
543
+ r[v_infos.count, r.count].map do |v|
563
544
  next v if !v || Marty::DataGrid.
564
545
  find_class_instance(pt, c_data_type, v)
565
546
 
@@ -571,9 +552,9 @@ class Marty::DataGrid < Marty::Base
571
552
  [metadata, data, data_type, lenient]
572
553
  end
573
554
 
574
- def self.create_from_import(name, import_text, created_dt=nil)
555
+ def self.create_from_import(name, import_text, created_dt = nil)
575
556
  metadata, data, data_type, lenient = parse(created_dt, import_text, {})
576
- dg = self.new
557
+ dg = new
577
558
  dg.name = name
578
559
  dg.data = data
579
560
  dg.data_type = data_type
@@ -584,15 +565,16 @@ class Marty::DataGrid < Marty::Base
584
565
  dg
585
566
  end
586
567
 
587
- def update_from_import(name, import_text, created_dt=nil)
588
- metadata, data, data_type, lenient =
589
- self.class.parse(created_dt, import_text, {})
568
+ def update_from_import(name, import_text, created_dt = nil)
569
+ new_metadata, data, data_type, lenient =
570
+ self.class.parse(created_dt, import_text, {})
590
571
 
591
572
  self.name = name
592
573
  self.data = data
593
574
  self.data_type = data_type
594
575
  self.lenient = !!lenient
595
- self.metadata = metadata unless self.metadata == metadata # Otherwise changed will depend on order in hashes
576
+ # Otherwise changed will depend on order in hashes
577
+ self.metadata = new_metadata unless metadata == new_metadata
596
578
  self.created_dt = created_dt if created_dt
597
579
  save!
598
580
  end
@@ -600,17 +582,13 @@ class Marty::DataGrid < Marty::Base
600
582
  # FIXME: should be private
601
583
  def build_index
602
584
  # create indices for the metadata
603
- metadata.each do
604
- |inf|
605
-
606
- attr, type, keys = inf["attr"], inf["type"], inf["keys"]
585
+ metadata.each do |inf|
586
+ attr, type, keys = inf['attr'], inf['type'], inf['keys']
607
587
 
608
588
  # find index class
609
589
  idx_class = Marty::DataGrid.type_to_index(type)
610
590
 
611
- keys.each_with_index do
612
- |k, index|
613
-
591
+ keys.each_with_index do |k, index|
614
592
  gi = idx_class.new
615
593
  gi.attr = attr
616
594
  gi.key = k
@@ -623,16 +601,16 @@ class Marty::DataGrid < Marty::Base
623
601
  end
624
602
 
625
603
  def self.modify_grid(params, metadata, data)
626
- removes = ["h", "v"].each_with_object({}) {|dir, hash| hash[dir] = Set.new}
604
+ removes = ['h', 'v'].each_with_object({}) { |dir, hash| hash[dir] = Set.new }
627
605
 
628
606
  metadata_copy, data_copy = metadata.deep_dup, data.deep_dup
629
607
 
630
608
  metadata_copy.each do |meta|
631
609
  dir, keys, type, rs_keep = meta.values_at(
632
- "dir", "keys", "type", "rs_keep")
610
+ 'dir', 'keys', 'type', 'rs_keep')
633
611
  next unless rs_keep
634
612
 
635
- if type == "numrange" || type == "int4range"
613
+ if type == 'numrange' || type == 'int4range'
636
614
  modop, modvalparm = parse_bounds(rs_keep)
637
615
  modval = params[modvalparm]
638
616
  if modval
@@ -652,23 +630,23 @@ class Marty::DataGrid < Marty::Base
652
630
 
653
631
  removes.reject! { |dir, set| set.empty? }
654
632
 
655
- removes.each do
656
- |dir, set|
657
- metadata_copy.select { |m| m["dir"] == dir }.each do |meta|
658
- meta["keys"] = remove_indices(meta["keys"], removes[dir])
633
+ removes.each do |dir, set|
634
+ metadata_copy.select { |m| m['dir'] == dir }.each do |meta|
635
+ meta['keys'] = remove_indices(meta['keys'], removes[dir])
659
636
  end
660
637
  end
661
638
 
662
- data_copy = remove_indices(data_copy, removes["v"]) if removes["v"]
639
+ data_copy = remove_indices(data_copy, removes['v']) if removes['v']
663
640
 
664
641
  data_copy.each_index do |index|
665
- data_copy[index] = remove_indices(data_copy[index], removes["h"])
666
- end if removes["h"]
642
+ data_copy[index] = remove_indices(data_copy[index], removes['h'])
643
+ end if removes['h']
667
644
 
668
645
  [data_copy, metadata_copy]
669
646
  end
670
647
 
671
648
  private
649
+
672
650
  def self.remove_indices(orig_array, inds)
673
651
  orig_array.each_with_object([]).with_index do |(item, new_array), index|
674
652
  new_array.push(item) unless inds.include?(index)
@@ -731,7 +709,6 @@ class Marty::DataGrid < Marty::Base
731
709
  prune_a.push(index)
732
710
  end
733
711
  end
734
-
735
712
  end
736
713
  [prune_a, rewrite_a]
737
714
  end
@@ -741,7 +718,6 @@ class Marty::DataGrid < Marty::Base
741
718
  prune_a, rewrite_a, value = [], [], Array(val)
742
719
 
743
720
  keys.each_with_index do |key, index|
744
-
745
721
  # rewrite any nil (wildcard) keys in the dimension
746
722
  # to be our 'to-keep' val(s)
747
723
  if key.nil?