drgdsl 1.1.0 → 1.2.0

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: a9715079e711fd5f608888b4b6433221db58145b85d58562e5419170496201c1
4
- data.tar.gz: 7c83b0126a22e86431e5d8ededa65b75cb982d8fdd8b1dd2db726308c94e5b25
3
+ metadata.gz: 346dd382500a954f17d93e1d1385e6cb8af10b02059298776973f0af8389686d
4
+ data.tar.gz: 3add8eaaa026e2bd054c230933be1e546592da9c919b67155e35165025a89e5a
5
5
  SHA512:
6
- metadata.gz: 8051b841182ad48e4e13f57bd06bfe999f694321c1abd3c88d16065a6149d0c80d357d6a6e75fd0d56f96356bc16fabaf85f321da6a7deb66d7510e8cb8695a9
7
- data.tar.gz: af4454d07118b2966da5074332d7549fda5b9ffc3fafae56dd151f86d40342ae23be3d089967d68e0ddcf6d8c6a7c1d388fba19b6aa61718d72ad9d1dc9f4b29
6
+ metadata.gz: f7fda718baaaa0077ed81705b6178a11b8ba8d170b19d53aa7b4fc61d1ed86f18514ec153422b9406d4b429b5d53f467fb91e92dec3e4289d2ded36f1b6eae5f
7
+ data.tar.gz: '00138b8f522e3c277163a86724a011e92e83845aae9a9fd6fdf67921b7f0bc7dde2030de8f78ed80bf4756dd2765a109057e1a41e724e8333fe907dd2394ec31'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- drgdsl (1.1.0)
4
+ drgdsl (1.2.0)
5
5
  oj (~> 3.5.0)
6
6
  parslet (~> 1.8.2)
7
7
 
data/bin/cache ADDED
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require "bundler/setup"
6
+ require "drgdsl"
7
+ require 'benchmark'
8
+
9
+ string_printer = DrgDSL::PrettyPrinter.new(output_format: :string)
10
+ html_printer = DrgDSL::PrettyPrinter.new(output_format: :html)
11
+ bash_printer = DrgDSL::PrettyPrinter.new(output_format: :bash)
12
+
13
+ asts = File.read('./test/expressions.txt', encoding: 'utf-8')
14
+ .split("\n\n")
15
+ .map { |exp| DrgDSL.parse(exp) }
16
+
17
+ N = 2
18
+
19
+ puts "Pretty printing #{N} * #{asts.count} ASTs:"
20
+
21
+ t1 = Benchmark.realtime do
22
+ N.times do
23
+ asts.each do |ast|
24
+ ast.accept(string_printer)
25
+ ast.accept(html_printer)
26
+ ast.accept(bash_printer)
27
+ end
28
+ end
29
+ end
30
+ puts "PrettyPrinter while building up cache: \t#{t1}"
31
+
32
+ t2 = Benchmark.realtime do
33
+ N.times do
34
+ asts.each do |ast|
35
+ ast.accept(string_printer)
36
+ ast.accept(html_printer)
37
+ ast.accept(bash_printer)
38
+ end
39
+ end
40
+ end
41
+ puts "PrettyPrinter with cache hits only: \t#{t2}"
42
+
43
+ [string_printer, html_printer, bash_printer].each do |printer|
44
+ class << printer
45
+ def cache?
46
+ false
47
+ end
48
+ end
49
+ end
50
+
51
+ t3 = Benchmark.realtime do
52
+ N.times do
53
+ asts.each do |ast|
54
+ ast.accept(string_printer)
55
+ ast.accept(html_printer)
56
+ ast.accept(bash_printer)
57
+ end
58
+ end
59
+ end
60
+ puts "PrettyPrinter with caching disabled: \t#{t3}"
61
+
62
+ puts "Speed increase when enabling caching: \t#{(100 / t3 * (t3 - t1)).round(2)}%"
63
+ puts "Speed increase when cache fully built up: \t#{(100 / t3 * (t3 - t2)).round(2)}%"
data/bin/html CHANGED
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ # frozen_string_literal: true
4
+
3
5
  # Generates highlighted html snippets for a bunch of expressions for
4
6
  # visualization purposes.
5
7
 
data/lib/drgdsl/ast.rb CHANGED
@@ -1,9 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DrgDSL
2
4
 
3
5
  # Nodes in DRG logic AST.
4
6
  #
5
7
  # @see AstBuilder
6
8
  module Ast
9
+ def self.node_classes
10
+ Node.node_classes
11
+ end
12
+
7
13
  module Node
8
14
  class << self
9
15
  def node_classes
@@ -46,6 +52,19 @@ module DrgDSL
46
52
  raise NotImplementedError
47
53
  end
48
54
 
55
+ # @return [Integer] object hash for this AST node. Node instances for the
56
+ # same expression should always return the same hash code. This is
57
+ # useful for optimizations.
58
+ def hash
59
+ raise NotImplementedError
60
+ end
61
+
62
+ def ==(other)
63
+ type == other.type && hash == other.hash
64
+ end
65
+
66
+ alias eql? ==
67
+
49
68
  def pretty_print(**pretty_printer_options)
50
69
  accept PrettyPrinter.new(**pretty_printer_options)
51
70
  end
@@ -79,6 +98,10 @@ module DrgDSL
79
98
  def to_hash
80
99
  { or: [expressions.map(&:to_hash)] }
81
100
  end
101
+
102
+ def hash
103
+ @hash ||= [type, *expressions].hash
104
+ end
82
105
  end
83
106
 
84
107
  # Represents a list of expressions joined with an "AND",
@@ -93,7 +116,11 @@ module DrgDSL
93
116
  end
94
117
 
95
118
  def to_hash
96
- { and: [ expressions.map(&:to_hash) ] }
119
+ { and: [expressions.map(&:to_hash)] }
120
+ end
121
+
122
+ def hash
123
+ @hash ||= [type, *expressions].hash
97
124
  end
98
125
  end
99
126
 
@@ -110,6 +137,10 @@ module DrgDSL
110
137
  def to_hash
111
138
  { paren: expression.to_hash }
112
139
  end
140
+
141
+ def hash
142
+ @hash ||= [type, expression].hash
143
+ end
113
144
  end
114
145
 
115
146
  # A NotExpression is a logic text of the form
@@ -126,6 +157,10 @@ module DrgDSL
126
157
  def to_hash
127
158
  { not: expression.to_hash }
128
159
  end
160
+
161
+ def hash
162
+ @hash ||= [type, expression].hash
163
+ end
129
164
  end
130
165
 
131
166
  # "Komplizierende_Prozeduren", "Dialyse", ...
@@ -141,6 +176,10 @@ module DrgDSL
141
176
  def to_hash
142
177
  { function_call: name }
143
178
  end
179
+
180
+ def hash
181
+ @hash ||= [type, name].hash
182
+ end
144
183
  end
145
184
 
146
185
  # A drg link originates from the grammar rule basic_or_drg_link
@@ -160,6 +199,10 @@ module DrgDSL
160
199
  def to_hash
161
200
  { drg_link: { var: variable.to_hash, name: name } }
162
201
  end
202
+
203
+ def hash
204
+ @hash ||= [type, name, variable].hash
205
+ end
163
206
  end
164
207
 
165
208
  # A BasicExpression consists of a variable and a condition
@@ -187,9 +230,14 @@ module DrgDSL
187
230
  def to_hash
188
231
  { basic: { var: variable.to_hash, condition: condition.to_hash } }
189
232
  end
233
+
234
+ def hash
235
+ @hash ||= [type, variable, condition].hash
236
+ end
190
237
  end
191
238
 
192
- # A comparison is either from a table_condition, a condition or a date_expression
239
+ # A comparison is either from a table_condition, a condition or a
240
+ # date_expression
193
241
  class Comparison
194
242
  include Node
195
243
 
@@ -210,6 +258,10 @@ module DrgDSL
210
258
  }
211
259
  }
212
260
  end
261
+
262
+ def hash
263
+ @hash ||= [type, op, value, table_condition].hash
264
+ end
213
265
  end
214
266
 
215
267
  # Has a certain operator (i.e. not / different) and a condition
@@ -227,13 +279,17 @@ module DrgDSL
227
279
  end
228
280
 
229
281
  def to_hash
230
- {
282
+ {
231
283
  unary_condition: {
232
284
  op: op,
233
285
  condition: condition.to_hash
234
286
  }
235
287
  }
236
288
  end
289
+
290
+ def hash
291
+ @hash ||= [type, op, condition].hash
292
+ end
237
293
  end
238
294
 
239
295
  class Empty
@@ -242,15 +298,21 @@ module DrgDSL
242
298
  def to_hash
243
299
  { empty: nil }
244
300
  end
301
+
302
+ def hash
303
+ @hash ||= type.hash
304
+ end
245
305
  end
246
306
 
247
- # There are 3 variants of table conditions (in_table, in_tables, all_in_table)
248
- # A table condition can have an optional comparison.
249
- # Tables refers to the table names (the internal names)
307
+ # There are 3 variants of table conditions (in_table, in_tables,
308
+ # all_in_table)
309
+ #
310
+ # A table condition can have an optional comparison. Tables refers to the
311
+ # table names (the internal names)
250
312
  class TableCondition
251
- IN_TABLE = 'in table'.freeze
252
- IN_TABLES = 'in tables'.freeze
253
- ALL_IN_TABLE = 'all in table'.freeze
313
+ IN_TABLE = 'in table'
314
+ IN_TABLES = 'in tables'
315
+ ALL_IN_TABLE = 'all in table'
254
316
 
255
317
  include Node
256
318
 
@@ -273,6 +335,10 @@ module DrgDSL
273
335
  }
274
336
  }
275
337
  end
338
+
339
+ def hash
340
+ @hash ||= [type, op, *tables, comparison].hash
341
+ end
276
342
  end
277
343
 
278
344
  # INFO: srg (prozedur) l (links) r (rechts) b(beidseitig)
@@ -294,17 +360,21 @@ module DrgDSL
294
360
  }
295
361
  }
296
362
  end
363
+
364
+ def hash
365
+ @hash ||= [type, variable, condition].hash
366
+ end
297
367
  end
298
368
 
299
369
  class DateExpression
300
370
  include Node
301
371
 
302
372
  attr_reader :left_variable,
303
- :right_variable,
304
- :left_condition,
305
- :right_condition,
306
- :comparison,
307
- :opd
373
+ :right_variable,
374
+ :left_condition,
375
+ :right_condition,
376
+ :comparison,
377
+ :opd
308
378
 
309
379
  # @param opd [String] E.g. "opd4" => "mind. 4 erfüllen" query
310
380
  def initialize(left_variable:,
@@ -312,8 +382,7 @@ module DrgDSL
312
382
  left_condition:,
313
383
  right_condition: nil,
314
384
  comparison:,
315
- opd:
316
- )
385
+ opd:)
317
386
 
318
387
  @left_variable = left_variable
319
388
  @right_variable = right_variable
@@ -335,6 +404,18 @@ module DrgDSL
335
404
  }
336
405
  }
337
406
  end
407
+
408
+ def hash
409
+ @hash ||= [
410
+ type,
411
+ left_variable,
412
+ right_variable,
413
+ left_condition,
414
+ right_condition,
415
+ comparison,
416
+ opd
417
+ ].hash
418
+ end
338
419
  end
339
420
 
340
421
  # "PDX", "AGEYEARS", ...
@@ -350,6 +431,10 @@ module DrgDSL
350
431
  def to_hash
351
432
  { name: name }
352
433
  end
434
+
435
+ def hash
436
+ @hash ||= [type, name].hash
437
+ end
353
438
  end
354
439
 
355
440
  # "3", "'MDC'", ...
@@ -369,6 +454,10 @@ module DrgDSL
369
454
  def to_hash
370
455
  { constant: { value: value } }
371
456
  end
457
+
458
+ def hash
459
+ @hash ||= [type, value].hash
460
+ end
372
461
  end
373
462
  end
374
463
  end
data/lib/drgdsl/parser.rb CHANGED
@@ -171,7 +171,7 @@ module DrgDSL
171
171
 
172
172
  # condition
173
173
  # ::= comparison
174
- # | unary_operator
174
+ # | unary_condition
175
175
  # | empty
176
176
  # | table_condition
177
177
  rule(:condition) do
@@ -52,6 +52,20 @@ module DrgDSL
52
52
  ''
53
53
  end
54
54
 
55
+ def cache?
56
+ true
57
+ end
58
+
59
+ def cache_key(n)
60
+ [
61
+ n.hash,
62
+ @indentation_level,
63
+ @indentation_string,
64
+ @output_format,
65
+ @multiline
66
+ ].hash
67
+ end
68
+
55
69
  private
56
70
 
57
71
  def visit_Expression(n)
@@ -1,3 +1,3 @@
1
1
  module DrgDSL
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -1,9 +1,52 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DrgDSL
4
+
4
5
  # Mixin for Ast::Node visitors. Visits all child nodes and returns the
5
6
  # visited node by default.
6
7
  module Visitor
8
+ def self.included(visitor)
9
+ visitor.prepend Cache
10
+ visitor.extend ClassMethods
11
+ end
12
+
13
+ module Cache
14
+ # @param n [Ast::Node]
15
+ def visit(n)
16
+ return super(n) unless cache?
17
+ self.class.cache[cache_key(n)] ||= super(n)
18
+ end
19
+ end
20
+
21
+ module ClassMethods
22
+ # @return [Hash] in-memory Ruby Hash
23
+ def cache
24
+ @cache ||= {}
25
+ end
26
+
27
+ def clear_cache!
28
+ @cache = {}
29
+ end
30
+ end
31
+
32
+ # Whether this visitor should cache visit results. Note that one might need
33
+ # to override #cache_key(n) if a visit is not deterministic, e.g. when it
34
+ # depends on some instance variables.
35
+ #
36
+ # @see PrettyPrinter#cache_key
37
+ #
38
+ # @return [Boolean]
39
+ def cache?
40
+ false
41
+ end
42
+
43
+ # @param n [Ast::Node]
44
+ # @return [Integer] ideally an object hash
45
+ def cache_key(n)
46
+ n.hash
47
+ end
48
+
49
+ # @param n [Ast::Node]
7
50
  def visit(n)
8
51
  return visit_nil if n.nil?
9
52
  send("visit_#{n.type}", n)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: drgdsl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SwissDRG AG
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-07-11 00:00:00.000000000 Z
11
+ date: 2018-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parslet
@@ -138,6 +138,7 @@ files:
138
138
  - LICENSE.txt
139
139
  - README.md
140
140
  - Rakefile
141
+ - bin/cache
141
142
  - bin/console
142
143
  - bin/html
143
144
  - bin/setup