delorean_lang 2.3.0 → 2.4.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: aefcc15664badb32e23cd629f7888a3984cf3fd0c01a351b652a71094c5ff3fc
4
- data.tar.gz: b3391aa0c8a00c49487ba6039838e9fd1e98f172539e06bbbb810b8c9e8cc737
3
+ metadata.gz: 84e137368e1c85b7005b7662f33e54e7cf6c7f1b0eb7fd2e3ebc8d9ebfbd8a04
4
+ data.tar.gz: 1b2039558b54352be0a030a2992aa50fc99c498fe3c1a96c84e36f9b4febb194
5
5
  SHA512:
6
- metadata.gz: beea3a643c91eaa8374ce126d0e07836545b7e141174ec38a05030b0b45b087fc48ba2ad880ce65a101125de9889c9ff67cfe786e752b0ebfff6127dbbc56633
7
- data.tar.gz: f3562421c5d037bf42da11f215b5f2c6d78c5c9987db1c0e1efdecaeb8c33c7f9ad38ad2b63db9b2d137b7179552b47ef99f0eb88d031d1ea98fb1fb9409f0c3
6
+ metadata.gz: 641d20f5de1251faaae77f7e571e6c2d43de03cc314d450b1c6246e00074c4fcb6a59506615d67968cc73b627901eedb7b3ee6375353b4a59e488ff43e4d06b7
7
+ data.tar.gz: 85afcad55380bb346f84fae8aa7e8b29601e28fe6a55e1f04d1bd9b968c064d40ab7235e2c19cf9791b3c7dc6b33d9339428e1809e9f51d5e81f1f7fea5cde9a
@@ -83,6 +83,12 @@ module Delorean
83
83
  end
84
84
 
85
85
  class BaseClass
86
+ def self._safe_navigation_get_attr(obj, attr, _e)
87
+ return nil if obj.nil?
88
+
89
+ _get_attr(obj, attr, _e)
90
+ end
91
+
86
92
  def self._get_attr(obj, attr, _e)
87
93
  # REALLY FIXME: this really needs to be another "when" in the
88
94
  # case statement below. However, Gemini appears to create Hash
@@ -195,6 +201,11 @@ module Delorean
195
201
  end
196
202
 
197
203
  ######################################################################
204
+ def self._safe_navigation_instance_call(obj, method, args, _e, &block)
205
+ return nil if obj.nil?
206
+
207
+ _instance_call(obj, method, args, _e, &block)
208
+ end
198
209
 
199
210
  def self._instance_call(obj, method, args, _e, &block)
200
211
  begin
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'delorean/cache/adapters/ruby_cache'
4
+ require 'delorean/cache/adapters/no_cache'
4
5
 
5
6
  module Delorean
6
7
  module Cache
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './base'
4
+
5
+ module Delorean
6
+ module Cache
7
+ module Adapters
8
+ class NoCache < ::Delorean::Cache::Adapters::Base
9
+ attr_reader :lookup_cache, :size_per_class
10
+
11
+ def initialize(size_per_class: 1000); end
12
+
13
+ def cache_item?(klass:, method_name:, args:)
14
+ false
15
+ end
16
+
17
+ def cache_item(klass:, cache_key:, item:); end
18
+
19
+ def fetch_item(klass:, cache_key:, default: nil)
20
+ default
21
+ end
22
+
23
+ def cache_key(klass:, method_name:, args:)
24
+ :no_cache_key
25
+ end
26
+
27
+ def clear!(klass:); end
28
+
29
+ def clear_all!; end
30
+
31
+ private
32
+
33
+ def clear_outdated_items(klass:); end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1764,6 +1764,17 @@ module Delorean
1764
1764
  elements[2]
1765
1765
  end
1766
1766
 
1767
+ def al
1768
+ elements[5]
1769
+ end
1770
+
1771
+ end
1772
+
1773
+ module DotExp5
1774
+ def i
1775
+ elements[2]
1776
+ end
1777
+
1767
1778
  def b_args
1768
1779
  elements[3]
1769
1780
  end
@@ -1773,7 +1784,13 @@ module Delorean
1773
1784
  end
1774
1785
  end
1775
1786
 
1776
- module DotExp5
1787
+ module DotExp6
1788
+ def i
1789
+ elements[2]
1790
+ end
1791
+ end
1792
+
1793
+ module DotExp7
1777
1794
  def i
1778
1795
  elements[2]
1779
1796
  end
@@ -2092,11 +2109,11 @@ module Delorean
2092
2109
  r0 = r35
2093
2110
  else
2094
2111
  i48, s48 = index, []
2095
- if (match_len = has_terminal?('.', false, index))
2096
- r49 = true
2112
+ if (match_len = has_terminal?('&.', false, index))
2113
+ r49 = instantiate_node(SyntaxNode,input, index...(index + match_len))
2097
2114
  @index += match_len
2098
2115
  else
2099
- terminal_parse_failure('\'.\'')
2116
+ terminal_parse_failure('\'&.\'')
2100
2117
  r49 = nil
2101
2118
  end
2102
2119
  s48 << r49
@@ -2112,40 +2129,56 @@ module Delorean
2112
2129
  r52 = _nt_identifier
2113
2130
  s48 << r52
2114
2131
  if r52
2115
- s53, i53 = [], index
2116
- loop do
2117
- r54 = _nt_block_args
2118
- if r54
2119
- s53 << r54
2120
- else
2121
- break
2122
- end
2132
+ if (match_len = has_terminal?('(', false, index))
2133
+ r53 = true
2134
+ @index += match_len
2135
+ else
2136
+ terminal_parse_failure('\'(\'')
2137
+ r53 = nil
2123
2138
  end
2124
- r53 = instantiate_node(SyntaxNode,input, i53...index, s53)
2125
2139
  s48 << r53
2126
2140
  if r53
2127
- s55, i55 = [], index
2128
- loop do
2129
- r56 = _nt_block_formulas
2130
- if r56
2131
- s55 << r56
2141
+ r55 = _nt_sp
2142
+ if r55
2143
+ r54 = r55
2144
+ else
2145
+ r54 = instantiate_node(SyntaxNode,input, index...index)
2146
+ end
2147
+ s48 << r54
2148
+ if r54
2149
+ r57 = _nt_fn_args
2150
+ if r57
2151
+ r56 = r57
2132
2152
  else
2133
- break
2153
+ r56 = instantiate_node(SyntaxNode,input, index...index)
2154
+ end
2155
+ s48 << r56
2156
+ if r56
2157
+ r59 = _nt_sp
2158
+ if r59
2159
+ r58 = r59
2160
+ else
2161
+ r58 = instantiate_node(SyntaxNode,input, index...index)
2162
+ end
2163
+ s48 << r58
2164
+ if r58
2165
+ if (match_len = has_terminal?(')', false, index))
2166
+ r60 = true
2167
+ @index += match_len
2168
+ else
2169
+ terminal_parse_failure('\')\'')
2170
+ r60 = nil
2171
+ end
2172
+ s48 << r60
2173
+ end
2134
2174
  end
2135
2175
  end
2136
- if s55.empty?
2137
- @index = i55
2138
- r55 = nil
2139
- else
2140
- r55 = instantiate_node(SyntaxNode,input, i55...index, s55)
2141
- end
2142
- s48 << r55
2143
2176
  end
2144
2177
  end
2145
2178
  end
2146
2179
  end
2147
2180
  if s48.last
2148
- r48 = instantiate_node(BlockExpression,input, i48...index, s48)
2181
+ r48 = instantiate_node(SafeNavigationCall,input, i48...index, s48)
2149
2182
  r48.extend(DotExp4)
2150
2183
  else
2151
2184
  @index = i48
@@ -2155,55 +2188,168 @@ module Delorean
2155
2188
  r48 = SyntaxNode.new(input, (index-1)...index) if r48 == true
2156
2189
  r0 = r48
2157
2190
  else
2158
- i57, s57 = index, []
2191
+ i61, s61 = index, []
2159
2192
  if (match_len = has_terminal?('.', false, index))
2160
- r58 = true
2193
+ r62 = true
2161
2194
  @index += match_len
2162
2195
  else
2163
2196
  terminal_parse_failure('\'.\'')
2164
- r58 = nil
2197
+ r62 = nil
2165
2198
  end
2166
- s57 << r58
2167
- if r58
2168
- r60 = _nt_sp
2169
- if r60
2170
- r59 = r60
2199
+ s61 << r62
2200
+ if r62
2201
+ r64 = _nt_sp
2202
+ if r64
2203
+ r63 = r64
2171
2204
  else
2172
- r59 = instantiate_node(SyntaxNode,input, index...index)
2205
+ r63 = instantiate_node(SyntaxNode,input, index...index)
2173
2206
  end
2174
- s57 << r59
2175
- if r59
2176
- i61 = index
2177
- r62 = _nt_identifier
2178
- if r62
2179
- r62 = SyntaxNode.new(input, (index-1)...index) if r62 == true
2180
- r61 = r62
2181
- else
2182
- r63 = _nt_integer
2183
- if r63
2184
- r63 = SyntaxNode.new(input, (index-1)...index) if r63 == true
2185
- r61 = r63
2186
- else
2187
- @index = i61
2188
- r61 = nil
2207
+ s61 << r63
2208
+ if r63
2209
+ r65 = _nt_identifier
2210
+ s61 << r65
2211
+ if r65
2212
+ s66, i66 = [], index
2213
+ loop do
2214
+ r67 = _nt_block_args
2215
+ if r67
2216
+ s66 << r67
2217
+ else
2218
+ break
2219
+ end
2220
+ end
2221
+ r66 = instantiate_node(SyntaxNode,input, i66...index, s66)
2222
+ s61 << r66
2223
+ if r66
2224
+ s68, i68 = [], index
2225
+ loop do
2226
+ r69 = _nt_block_formulas
2227
+ if r69
2228
+ s68 << r69
2229
+ else
2230
+ break
2231
+ end
2232
+ end
2233
+ if s68.empty?
2234
+ @index = i68
2235
+ r68 = nil
2236
+ else
2237
+ r68 = instantiate_node(SyntaxNode,input, i68...index, s68)
2238
+ end
2239
+ s61 << r68
2189
2240
  end
2190
2241
  end
2191
- s57 << r61
2192
2242
  end
2193
2243
  end
2194
- if s57.last
2195
- r57 = instantiate_node(GetAttr,input, i57...index, s57)
2196
- r57.extend(DotExp5)
2244
+ if s61.last
2245
+ r61 = instantiate_node(BlockExpression,input, i61...index, s61)
2246
+ r61.extend(DotExp5)
2197
2247
  else
2198
- @index = i57
2199
- r57 = nil
2248
+ @index = i61
2249
+ r61 = nil
2200
2250
  end
2201
- if r57
2202
- r57 = SyntaxNode.new(input, (index-1)...index) if r57 == true
2203
- r0 = r57
2251
+ if r61
2252
+ r61 = SyntaxNode.new(input, (index-1)...index) if r61 == true
2253
+ r0 = r61
2204
2254
  else
2205
- @index = i0
2206
- r0 = nil
2255
+ i70, s70 = index, []
2256
+ if (match_len = has_terminal?('.', false, index))
2257
+ r71 = true
2258
+ @index += match_len
2259
+ else
2260
+ terminal_parse_failure('\'.\'')
2261
+ r71 = nil
2262
+ end
2263
+ s70 << r71
2264
+ if r71
2265
+ r73 = _nt_sp
2266
+ if r73
2267
+ r72 = r73
2268
+ else
2269
+ r72 = instantiate_node(SyntaxNode,input, index...index)
2270
+ end
2271
+ s70 << r72
2272
+ if r72
2273
+ i74 = index
2274
+ r75 = _nt_identifier
2275
+ if r75
2276
+ r75 = SyntaxNode.new(input, (index-1)...index) if r75 == true
2277
+ r74 = r75
2278
+ else
2279
+ r76 = _nt_integer
2280
+ if r76
2281
+ r76 = SyntaxNode.new(input, (index-1)...index) if r76 == true
2282
+ r74 = r76
2283
+ else
2284
+ @index = i74
2285
+ r74 = nil
2286
+ end
2287
+ end
2288
+ s70 << r74
2289
+ end
2290
+ end
2291
+ if s70.last
2292
+ r70 = instantiate_node(GetAttr,input, i70...index, s70)
2293
+ r70.extend(DotExp6)
2294
+ else
2295
+ @index = i70
2296
+ r70 = nil
2297
+ end
2298
+ if r70
2299
+ r70 = SyntaxNode.new(input, (index-1)...index) if r70 == true
2300
+ r0 = r70
2301
+ else
2302
+ i77, s77 = index, []
2303
+ if (match_len = has_terminal?('&.', false, index))
2304
+ r78 = instantiate_node(SyntaxNode,input, index...(index + match_len))
2305
+ @index += match_len
2306
+ else
2307
+ terminal_parse_failure('\'&.\'')
2308
+ r78 = nil
2309
+ end
2310
+ s77 << r78
2311
+ if r78
2312
+ r80 = _nt_sp
2313
+ if r80
2314
+ r79 = r80
2315
+ else
2316
+ r79 = instantiate_node(SyntaxNode,input, index...index)
2317
+ end
2318
+ s77 << r79
2319
+ if r79
2320
+ i81 = index
2321
+ r82 = _nt_identifier
2322
+ if r82
2323
+ r82 = SyntaxNode.new(input, (index-1)...index) if r82 == true
2324
+ r81 = r82
2325
+ else
2326
+ r83 = _nt_integer
2327
+ if r83
2328
+ r83 = SyntaxNode.new(input, (index-1)...index) if r83 == true
2329
+ r81 = r83
2330
+ else
2331
+ @index = i81
2332
+ r81 = nil
2333
+ end
2334
+ end
2335
+ s77 << r81
2336
+ end
2337
+ end
2338
+ if s77.last
2339
+ r77 = instantiate_node(SafeNavigationGetAttr,input, i77...index, s77)
2340
+ r77.extend(DotExp7)
2341
+ else
2342
+ @index = i77
2343
+ r77 = nil
2344
+ end
2345
+ if r77
2346
+ r77 = SyntaxNode.new(input, (index-1)...index) if r77 == true
2347
+ r0 = r77
2348
+ else
2349
+ @index = i0
2350
+ r0 = nil
2351
+ end
2352
+ end
2207
2353
  end
2208
2354
  end
2209
2355
  end
@@ -83,10 +83,14 @@ grammar Delorean
83
83
  '.' sp? i:identifier '(' sp? al:fn_args? sp? ')' b_args:block_args* expressions:block_formulas+ <BlockExpression>
84
84
  /
85
85
  '.' sp? i:identifier '(' sp? al:fn_args? sp? ')' <Call>
86
+ /
87
+ '&.' sp? i:identifier '(' sp? al:fn_args? sp? ')' <SafeNavigationCall>
86
88
  /
87
89
  '.' sp? i:identifier b_args:block_args* expressions:block_formulas+ <BlockExpression>
88
90
  /
89
91
  '.' sp? i:(identifier / integer) <GetAttr>
92
+ /
93
+ '&.' sp? i:(identifier / integer) <SafeNavigationGetAttr>
90
94
  end
91
95
 
92
96
  rule unpack_args
@@ -45,6 +45,7 @@ module Delorean
45
45
  cache_key = delorean_cache_adapter.cache_key(
46
46
  klass: self, method_name: name, args: args
47
47
  )
48
+
48
49
  cached_item = delorean_cache_adapter.fetch_item(
49
50
  klass: self, cache_key: cache_key, default: :NF
50
51
  )
@@ -395,6 +395,14 @@ eos
395
395
  end
396
396
  end
397
397
 
398
+ class SafeNavigationGetAttr < GetAttr
399
+ def rewrite(_context, vcode)
400
+ attr = i.text_value
401
+ attr = "'#{attr}'" unless /\A[0-9]+\z/.match?(attr)
402
+ "_safe_navigation_get_attr(#{vcode}, #{attr}, _e)"
403
+ end
404
+ end
405
+
398
406
  class Call < SNode
399
407
  def check(context, *)
400
408
  al.text_value.empty? ? [] : al.check(context)
@@ -420,6 +428,29 @@ eos
420
428
  end
421
429
  end
422
430
 
431
+ class SafeNavigationCall < Call
432
+ def rewrite(context, vcode)
433
+ if al.text_value.empty?
434
+ args_str = ''
435
+ arg_count = 0
436
+ else
437
+ args_str = al.rewrite(context)
438
+ arg_count = al.arg_count
439
+ end
440
+
441
+ if vcode.is_a?(ClassText)
442
+ # FIXME: Do we really need this check here?
443
+ # ruby class call
444
+ class_name = vcode.text
445
+ context.parse_check_call_fn(i.text_value, arg_count, class_name)
446
+ end
447
+
448
+ "_safe_navigation_instance_call(
449
+ #{vcode}, '#{i.text_value}', [#{args_str}], _e
450
+ )"
451
+ end
452
+ end
453
+
423
454
  class BlockParameter < Parameter
424
455
  def check(context)
425
456
  context.parse_define_var(i.text_value)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delorean
4
- VERSION = '2.3.0'
4
+ VERSION = '2.4.0'
5
5
  end
@@ -3,6 +3,10 @@
3
3
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
4
4
 
5
5
  describe 'Delorean cache' do
6
+ after do
7
+ ::Delorean::Cache.adapter = ::Delorean::Cache::Adapters::RubyCache.new
8
+ end
9
+
6
10
  before do
7
11
  Dummy.clear_lookup_cache!
8
12
  end
@@ -64,4 +68,19 @@ describe 'Delorean cache' do
64
68
  expect(item_10).to be_a(OpenStruct)
65
69
  expect(item_10['10']).to eq(10)
66
70
  end
71
+
72
+ describe 'No cache adapter' do
73
+ before do
74
+ ::Delorean::Cache.adapter = ::Delorean::Cache::Adapters::NoCache.new
75
+ end
76
+
77
+ it "doesn't use cache" do
78
+ expect(OpenStruct).to receive(:new).twice.and_call_original
79
+
80
+ res1 = Dummy.returns_cached_openstruct(1, 2)
81
+ res2 = Dummy.returns_cached_openstruct(1, 2)
82
+
83
+ expect(res1).to eq res2
84
+ end
85
+ end
67
86
  end
@@ -1588,6 +1588,29 @@ eof
1588
1588
  expect(r).to eq([[], 1])
1589
1589
  end
1590
1590
 
1591
+ it 'works with safe navigation' do
1592
+ engine.parse defn(*default_node,
1593
+ ' b = [1]',
1594
+ ' c = b[1] ',
1595
+ ' d = c&.round(1) ',
1596
+ ' e = c&.round ',
1597
+ ' f = c&.round(1)&.round(2)&.round(3) ',
1598
+ ' g = c&.round&.round&.round ',
1599
+ )
1600
+
1601
+ r = engine.evaluate('A', 'd')
1602
+ expect(r).to eq(nil)
1603
+
1604
+ r = engine.evaluate('A', 'e')
1605
+ expect(r).to eq(nil)
1606
+
1607
+ r = engine.evaluate('A', 'f')
1608
+ expect(r).to eq(nil)
1609
+
1610
+ r = engine.evaluate('A', 'g')
1611
+ expect(r).to eq(nil)
1612
+ end
1613
+
1591
1614
  describe 'methods' do
1592
1615
  it 'all?' do
1593
1616
  engine.parse defn(*default_node,
@@ -190,7 +190,7 @@ describe 'Delorean' do
190
190
  cache_factor = h['delorean_node_cache'] / h['delorean']
191
191
  # p cache_factor
192
192
 
193
- expected_cache_factor = ENV['COVERAGE'] ? 64 : 80
193
+ expected_cache_factor = ENV['COVERAGE'] ? 60 : 80
194
194
  expect(cache_factor).to be > expected_cache_factor
195
195
  end
196
196
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delorean_lang
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arman Bostani
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-17 00:00:00.000000000 Z
11
+ date: 2020-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -145,6 +145,7 @@ files:
145
145
  - lib/delorean/cache.rb
146
146
  - lib/delorean/cache/adapters.rb
147
147
  - lib/delorean/cache/adapters/base.rb
148
+ - lib/delorean/cache/adapters/no_cache.rb
148
149
  - lib/delorean/cache/adapters/ruby_cache.rb
149
150
  - lib/delorean/const.rb
150
151
  - lib/delorean/debug.rb