quby 5.0.0.pre2 → 5.0.0.pre3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d19ac693a1e2e0530ead24bd6154f8fb6bd29b7d12cac079cd605d3b79329ec
4
- data.tar.gz: d73d97a84f5b8d3fefd5655d3dc6663a069f4519c42f4cef3121b955630480f1
3
+ metadata.gz: 2ff840130087f113cabb79c809f8046fd434993e436da3efedcc397597c43979
4
+ data.tar.gz: f8b6977b5802b86e676d06fa13771a70919acab2538dbfbfe8a2a5808211da78
5
5
  SHA512:
6
- metadata.gz: a9e02fcd7b0116a1c38a34b611a8e460cfa052f83b6b977bfcf67ffb8a1851ac15b2394294266bc97da6892fd9f96edc105312a021dd708dffca8c23aa76d272
7
- data.tar.gz: 8cf3fb6290472a64a730747bd2b5824a952d012c679645d1ddc907754677e94c2dce93ee8b6892d8f4decc1ce13c81a3cba5debd05a8d7afaac3db292d15f832
6
+ metadata.gz: 178d14bdac8b8fd8b2ac1e45cb6dfdd8b22c2d5270d51a832c6c01e5eb1207e4ad498a448ddb2908c55f029c6d9db35e1c507f473548112c72bfa45deb25a56e
7
+ data.tar.gz: c7ea63e6170b68d8b0fc48340a9f5db3333908e9fb08086a0557670b89c77e50f4010565692038f7acc8c5c53a03e312c3fdc8416a5515f28c5b157056b3b9c0
@@ -27,7 +27,6 @@ and where it can store its answers.
27
27
  ```ruby
28
28
  Quby.questionnaire_repo = Quby::Questionnaires::Repos::DiskRepo.new(Rails.root.join("db/questionnaires/definitions"))
29
29
  Quby.answer_repo = Quby::Answers::Repos::MongoidRepo.new
30
- Quby.lookup_table_repo = Quby::LookupTableRepo::Disk.new(Rails.root.join("db/questionnaires/lookup_tables"))
31
30
  Quby::Settings.shared_secret = ENV["QUBY_SHARED_SECRET"]
32
31
  ```
33
32
 
@@ -38,14 +38,6 @@ module Quby
38
38
  @questionnaires_api = nil
39
39
  end
40
40
 
41
- def lookup_table_repo=(repo)
42
- @lookup_table_repo = repo
43
- end
44
-
45
- def lookup_table_repo
46
- @lookup_table_repo || fail("Quby does not have its lookup table repo (Quby.lookup_table_repo) configured.")
47
- end
48
-
49
41
  def fixtures_path
50
42
  File.expand_path File.join('..', '..', 'spec', 'fixtures'), __FILE__
51
43
  end
@@ -79,7 +71,7 @@ module Quby
79
71
  end
80
72
 
81
73
  require 'quby/settings'
74
+ require 'quby/table_backend/range_tree'
82
75
  require 'quby/questionnaires'
83
76
  require 'quby/answers'
84
- require 'quby/engine'
85
- require 'quby/lookup_table_repo'
77
+ require 'quby/engine'
@@ -82,7 +82,7 @@ module Quby
82
82
  attr_accessor :extra_question_values
83
83
  attr_accessor :extra_failed_validations
84
84
 
85
- def initialize(_id: nil, questionnaire_id: nil, questionnaire_key: nil,
85
+ def initialize(_id: nil, questionnaire_id: nil, questionnaire_key: nil, questionnaire: nil,
86
86
  raw_params: nil, value: nil, patient_id: nil, patient: nil,
87
87
  token: nil, active: true, test: false, created_at: nil, updated_at: nil,
88
88
  started_at: nil, completed_at: nil, outcome: nil, outcome_generated_at: nil,
@@ -111,6 +111,8 @@ module Quby
111
111
  self.import_notes = import_notes || {}
112
112
  self.flags = flags
113
113
  self.textvars = textvars
114
+
115
+ @questionnaire = questionnaire
114
116
  end
115
117
 
116
118
  def id
@@ -162,7 +164,7 @@ module Quby
162
164
 
163
165
  # Faux belongs_to :questionnaire
164
166
  def questionnaire
165
- Quby.questionnaires.find(questionnaire_key)
167
+ @questionnaire ||= Quby.questionnaires.find(questionnaire_key)
166
168
  end
167
169
 
168
170
  def mark_completed(start_time)
@@ -231,9 +231,7 @@ module Quby
231
231
  end
232
232
 
233
233
  def table_lookup(table_key, parameters)
234
- @questionnaire.lookup_tables[table_key] ||= Quby::LookupTable.new table_key
235
- @questionnaire.lookup_tables[table_key] \
236
- .lookup(parameters)
234
+ @questionnaire.lookup_tables.fetch(table_key).lookup(parameters)
237
235
  end
238
236
 
239
237
  # Public: Ensure given question_keys have answers. Strings with nothing but whitespace are
@@ -15,7 +15,6 @@ require 'jquery-ui-rails'
15
15
  require 'compass-blueprint'
16
16
 
17
17
  require 'susy'
18
- require 'quby/lookup_table'
19
18
  require 'quby/range_categories'
20
19
  require 'quby/pdf_renderer'
21
20
 
@@ -3,14 +3,16 @@
3
3
  module Quby
4
4
  module Questionnaires
5
5
  module DSL
6
+ # Deprecated, precompile elsewhere and use from_json
6
7
  def self.build_from_definition(definition)
7
- compiled = Quby::Compiler.compile(definition.key, definition.sourcecode, seeds: [], path: definition.path)
8
+ compiled = Quby::Compiler.compile(definition.key, definition.sourcecode, seeds: [], lookup_tables: {}, path: definition.path)
8
9
  data = JSON.parse(compiled[:outputs][:quby_frontend_v1].content)
9
10
  Deserializer.from_json(data)
10
11
  end
11
12
 
13
+ # Deprecated, precompile elsewhere and use from_json
12
14
  def self.build(key, sourcecode = nil, timestamp: nil, &block)
13
- compiled = Quby::Compiler.compile(key, sourcecode, seeds: [], &block)
15
+ compiled = Quby::Compiler.compile(key, sourcecode, seeds: [], lookup_tables: {}, &block)
14
16
  data = JSON.parse(compiled[:outputs][:quby_frontend_v1].content)
15
17
  Deserializer.from_json(data)
16
18
  end
@@ -2,8 +2,6 @@
2
2
 
3
3
  # A lookup tree to find values by multiple arguments.
4
4
  #
5
- # Created by LookupTable from a csv file or by add_lookup_tree from dsl.
6
- #
7
5
  # Example tree:
8
6
  # Inhibitie:
9
7
  # male:
@@ -36,27 +34,6 @@ module Quby::TableBackend
36
34
  @tree = tree
37
35
  end
38
36
 
39
- # load csv data into a tree.
40
- # each row is a path through the tree.
41
- # String and float types are used to make an exact match.
42
- # A range is always a range between two floats where the range is between
43
- # the low value (inclusive) and the high value (exclusive),
44
- # written as 4:5 (low:high). These boundaries can be given as floats or
45
- # integers, but internally they are always treated as a floats.
46
- # The low and high values of a range cannot be equal.
47
- # Use minfinity or infinity to create infinite ranges.
48
- #
49
- # @params levels [Array<String>] An array of column names
50
- # @param compare [Array<String>]An array of lookup types (string, float or range) for each column
51
- # @param data [Array<Array<>>] The rows describing a path through the tree.
52
- def self.from_csv(levels:, compare:, data:)
53
- tree = data.each_with_object({}) do |row, tree|
54
- add_to_tree(tree, row, levels, compare)
55
- end
56
- new(levels: levels, tree: tree)
57
- end
58
-
59
-
60
37
  # Given a parameters hash that contains a value or range for every
61
38
  # level in the tree, find and return the normscore.
62
39
  # ie. `lookup({age: 10, raw: 5, scale: 'Inhibitie', gender: 'male'})` => 39
@@ -67,34 +44,6 @@ module Quby::TableBackend
67
44
 
68
45
  private
69
46
 
70
- def self.add_to_tree(tree, (value, *path), (level, *levels), (compare, *compares))
71
- key = case compare
72
- when 'string' then value.to_s
73
- when 'float' then parse_float(value)
74
- when 'range' then create_range(value)
75
- end
76
-
77
- if levels.empty?
78
- return key
79
- end
80
-
81
- tree.merge! key => add_to_tree(tree[key] || {}, path, levels, compares)
82
- end
83
-
84
- def self.create_range(value)
85
- min, max = value.split(':').map { |val| parse_float(val) }
86
- fail 'Cannot create range between two equal values' if min == max
87
- (min...max)
88
- end
89
-
90
- def self.parse_float(value)
91
- case value
92
- when 'infinity' then Float::INFINITY
93
- when 'minfinity' then -Float::INFINITY
94
- else Float(value)
95
- end
96
- end
97
-
98
47
  # All parameters must be present to do a lookup but the order does not matter.
99
48
  def validate_parameters(parameters)
100
49
  if @levels[0...-1].sort != parameters.keys.map(&:to_s).sort
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Quby
4
- VERSION = "5.0.0.pre2"
4
+ VERSION = "5.0.0.pre3"
5
5
  end
@@ -485,26 +485,16 @@ module Quby::Answers::Services
485
485
  let(:calculator) { ScoreCalculator.new(questionnaire: questionnaire, values: {}, timestamp: timestamp) }
486
486
  let(:table_double) { double.as_null_object }
487
487
 
488
- before do
489
- allow(Quby::LookupTable).to receive(:new).and_return(table_double)
490
- end
491
-
492
- it 'instantiates a new Quby::Answers::Entities::LookupTable if the table_hash cache does not know the key' do
488
+ it 'raises an error if lookup table cannot be found' do
493
489
  expect(questionnaire.lookup_tables).to be_empty
494
- calculator.table_lookup :test_table, score: 1
495
- expect(questionnaire.lookup_tables[:test_table]).to be(table_double)
496
- end
497
-
498
- it 'uses the memoized lookuptable if there is a cache hit' do
499
- calculator.table_lookup :test_table, score: 1
500
- expect(table_double).to receive(:lookup)
501
- calculator.table_lookup :test_table, score: 1
490
+ expect { calculator.table_lookup :test_table, score: 1 }.to raise_error(KeyError)
502
491
  end
503
492
 
504
493
  it 'looks up the given parameters on the given table' do
494
+ questionnaire.lookup_tables[:test_table] = table_double
505
495
  parameters = {score: 1}
506
- expect(table_double).to receive(:lookup).with parameters
507
496
  calculator.table_lookup :test_table, parameters
497
+ expect(table_double).to have_received(:lookup).with parameters
508
498
  end
509
499
 
510
500
  context 'with add_lookup_tree inside dsl' do
@@ -1,17 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Quby::TableBackend::RangeTree do
4
- let(:csv_key) { 'test' }
5
- let(:data) { Quby.lookup_table_repo.retrieve(csv_key) }
6
- let(:tree) { described_class.from_csv(levels: data.shift, compare: data.shift, data: data) }
7
-
8
- describe '#from_csv' do
9
- context 'invalid csv data' do
10
- let(:csv_key) { 'bad_range' }
11
- it 'fails when csv data contains a range between two equal values' do
12
- expect { tree }.to raise_error(RuntimeError, 'Cannot create range between two equal values')
13
- end
14
- end
4
+ let(:tree) do
5
+ described_class.new(
6
+ levels: ["scale", "gender", "age", "raw", "norm"],
7
+ tree: {
8
+ "Inhibitie" => {
9
+ "male" => {
10
+ (10.0...11.0) => {
11
+ (-Float::INFINITY...10.0) => 39.0,
12
+ (10.0...20.0) => 42.0,
13
+ (20.0...30.0) => 71.0,
14
+ (30.0...Float::INFINITY) => 75.0
15
+ }
16
+ }
17
+ }
18
+ }
19
+ )
15
20
  end
16
21
 
17
22
  describe '#lookup' do
@@ -68,7 +73,23 @@ describe Quby::TableBackend::RangeTree do
68
73
  end
69
74
 
70
75
  describe 'definition containing range with float values' do
71
- let(:csv_key) { 'float_test' }
76
+ let(:tree) do
77
+ described_class.new(
78
+ levels: ["scale", "gender", "age", "raw", "norm"],
79
+ tree: {
80
+ "Inhibitie" => {
81
+ "male" => {
82
+ (10.0...11.0) => {
83
+ (-Float::INFINITY...10.5) => 39.0,
84
+ (10.5...20.1) => 42.0,
85
+ (20.1...30.7) => 71.0,
86
+ (30.7...Float::INFINITY) => 75.0
87
+ }
88
+ }
89
+ }
90
+ }
91
+ )
92
+ end
72
93
 
73
94
  it 'returns the correct scores' do
74
95
  params = {age: 10, raw: 15.8, scale: 'Inhibitie', gender: 'male'}
@@ -80,7 +101,12 @@ describe Quby::TableBackend::RangeTree do
80
101
  end
81
102
 
82
103
  describe 'definition containing float values' do
83
- let(:csv_key) { 'test2' }
104
+ let(:tree) do
105
+ described_class.new(
106
+ levels: ["scale", "raw", "norm"],
107
+ tree: {"Inhibitie" => {15.0=>39.0, 16.0=>42.0, 17.0=>71.0, 18.0=>75.0}}
108
+ )
109
+ end
84
110
 
85
111
  it 'returns the correct scores when using integers in lookup path' do
86
112
  params = {scale: 'Inhibitie', raw: 17}
@@ -94,6 +94,5 @@ RSpec.configure do |config|
94
94
  config.before(:each) do
95
95
  Quby.questionnaire_repo = Quby::Questionnaires::Repos::DiskRepo.new(Quby.fixtures_path)
96
96
  Quby.answer_repo = Quby::Answers::Repos::MemoryRepo.new
97
- Quby.lookup_table_repo = Quby::LookupTableRepo::Disk.new(Rails.root.join('..', 'fixtures', 'lookup_tables'))
98
97
  end
99
98
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quby
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0.pre2
4
+ version: 5.0.0.pre3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marten Veldthuis
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2020-10-27 00:00:00.000000000 Z
14
+ date: 2020-10-29 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rails
@@ -750,8 +750,6 @@ files:
750
750
  - lib/quby/answers/specs/api_specs.rb
751
751
  - lib/quby/answers/specs/repo_specs.rb
752
752
  - lib/quby/engine.rb
753
- - lib/quby/lookup_table.rb
754
- - lib/quby/lookup_table_repo.rb
755
753
  - lib/quby/markdown_parser.rb
756
754
  - lib/quby/pdf_renderer.rb
757
755
  - lib/quby/questionnaires.rb
@@ -810,7 +808,6 @@ files:
810
808
  - spec/active_model_modules/type_validator_spec.rb
811
809
  - spec/benchmarks/answer_instantiation_speed_spec.rb
812
810
  - spec/benchmarks/large_questionnaire_spec.rb
813
- - spec/benchmarks/load_normscore_csv.rb
814
811
  - spec/controllers/quby/answers_controller/authorize_with_hmac_spec.rb
815
812
  - spec/controllers/quby/answers_controller/authorize_with_id_from_session_spec.rb
816
813
  - spec/controllers/quby/answers_controller_spec.rb
@@ -6380,8 +6377,6 @@ files:
6380
6377
  - spec/quby/answers/services/text_transformation_spec.rb
6381
6378
  - spec/quby/answers/services/updates_answers_spec.rb
6382
6379
  - spec/quby/i18n_spec.rb
6383
- - spec/quby/lookup_table_repo_spec.rb
6384
- - spec/quby/lookup_table_spec.rb
6385
6380
  - spec/quby/markdown_parser_spec.rb
6386
6381
  - spec/quby/pdf_renderer_spec.rb
6387
6382
  - spec/quby/questionnaires/deserializer/questionnaire_spec.rb
@@ -6521,10 +6516,8 @@ test_files:
6521
6516
  - spec/quby/answers/entities/score_spec.rb
6522
6517
  - spec/quby/answers/entities/patient_spec.rb
6523
6518
  - spec/quby/answers/entities/answer_spec.rb
6524
- - spec/quby/lookup_table_spec.rb
6525
6519
  - spec/quby/pdf_renderer_spec.rb
6526
6520
  - spec/quby/markdown_parser_spec.rb
6527
- - spec/quby/lookup_table_repo_spec.rb
6528
6521
  - spec/spec.opts
6529
6522
  - spec/features/hiding_questions_spec.rb
6530
6523
  - spec/features/javascript_question_dependencies_spec.rb
@@ -12060,7 +12053,6 @@ test_files:
12060
12053
  - spec/support/validation_helpers.rb
12061
12054
  - spec/support/feature_helpers.rb
12062
12055
  - spec/benchmarks/large_questionnaire_spec.rb
12063
- - spec/benchmarks/load_normscore_csv.rb
12064
12056
  - spec/benchmarks/answer_instantiation_speed_spec.rb
12065
12057
  - spec/javascripts/ajax_callbacks_spec.coffee
12066
12058
  - spec/javascripts/init_questions_spec.coffee
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'quby/table_backend/range_tree'
4
-
5
- module Quby
6
- class LookupTable
7
- attr_accessor :key
8
-
9
- def initialize(key)
10
- @key = key
11
- end
12
-
13
- def backing
14
- return @backing if @backing.present?
15
- all_data = data
16
- headers = all_data.shift
17
- compare = all_data.shift
18
- @backing = Quby::TableBackend::RangeTree.from_csv(levels: headers, compare: compare, data: all_data)
19
- end
20
-
21
- def lookup(parameters)
22
- backing.lookup(parameters)
23
- end
24
-
25
- def data
26
- Quby.lookup_table_repo.retrieve(key)
27
- end
28
- end
29
- end
@@ -1,24 +0,0 @@
1
- require 'pathname'
2
- require 'csv'
3
-
4
- module Quby
5
- module LookupTableRepo
6
- def self.validate_key(key)
7
- raise 'invalid key' unless key =~ /\A[a-z][a-z_0-9]{1,50}\z/
8
- end
9
-
10
- class Disk
11
- attr_reader :disk_table_root
12
-
13
- def initialize(disk_table_root)
14
- @disk_table_root = Pathname.new(disk_table_root)
15
- end
16
-
17
- def retrieve(key)
18
- Quby::LookupTableRepo.validate_key(key)
19
- path = disk_table_root.join(key + '.csv')
20
- CSV.read(path, col_sep: ';', skip_blanks: true)
21
- end
22
- end
23
- end
24
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- feature 'Load normscore csv file', benchmark: true do
6
- it 'loads a csv file' do
7
- 10.times do
8
- Quby.lookup_table_repo.retrieve('test')
9
- end
10
- end
11
-
12
- it 'builds a tree' do
13
- data = Quby.lookup_table_repo.retrieve('test')
14
- 10.times do
15
- Quby::TableBackend::RangeTree.new(data).send :tree
16
- end
17
- end
18
- end
@@ -1,20 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Quby::LookupTableRepo::Disk do
4
- subject { Quby.lookup_table_repo }
5
-
6
- it 'Quby.lookup_table_repo is a disk repo by default' do
7
- expect(subject).to be_an_instance_of(described_class)
8
- end
9
-
10
- describe '#retrieve' do
11
- it 'reads the csv file' do
12
- expect(CSV).to receive(:read).and_call_original
13
- subject.retrieve 'test'
14
- end
15
-
16
- it 'fails when csv file is not found' do
17
- expect { subject.retrieve 'not_there' }.to raise_error(Errno::ENOENT)
18
- end
19
- end
20
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- module Quby
6
- describe LookupTable do
7
- let(:table) { described_class.new('test') }
8
- let(:fake_backing) { double(:"present?" => true).as_null_object }
9
-
10
- describe '#lookup' do
11
- it 'passes lookup calls on to the backing' do
12
- expect(Quby::TableBackend::RangeTree).to receive(:from_csv).and_return(fake_backing)
13
- parameters = {a: 1}
14
- expect(table.backing).to receive(:lookup).with(parameters)
15
- table.lookup(parameters)
16
- end
17
-
18
- it 'initializes the disktree lazily' do
19
- headers = double
20
- compare = double
21
- data = double
22
- data_double = [headers, compare, data]
23
- table
24
- expect_any_instance_of(described_class).to receive(:data).and_return(data_double)
25
- expect(Quby::TableBackend::RangeTree).to receive(:from_csv).with(levels: headers, compare: compare, data:[data]).and_return(fake_backing)
26
- table.lookup(some: :thing)
27
- end
28
- end
29
-
30
- describe '#data' do
31
- it 'calls Quby.lookup_table_repo.retrieve(table.key)' do
32
- table
33
- expect(Quby.lookup_table_repo).to receive(:retrieve).with(table.key)
34
- table.data
35
- end
36
- end
37
- end
38
- end