delorean_lang 0.5.3 → 0.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/README.md +30 -1
- data/delorean.gemspec +1 -0
- data/lib/delorean/base.rb +1 -1
- data/lib/delorean/engine.rb +2 -3
- data/lib/delorean/functions.rb +66 -0
- data/lib/delorean/model.rb +2 -66
- data/lib/delorean/version.rb +1 -1
- data/lib/delorean_lang.rb +2 -0
- data/spec/eval_spec.rb +14 -0
- data/spec/spec_helper.rb +12 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: afc7142d7683c1fe4d606a86dd7c46eff3ae672b1eb58db13cb587c18b9ea741
|
4
|
+
data.tar.gz: a522e77939cbcaa4b8592980ced9281179a07e171fe3e34b69adba13661a8215
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03b53dcf912b0311f12151e6fa189e797f767205cd36d6aac6547d58ab6fad6cfbe6905766caae199c15d4898360829a2249379d61634fec98062fc33753b8ae
|
7
|
+
data.tar.gz: d21c189ed7f03b98cc5c21525a1c031b4a6d43477291744a7016e75f411ca9aad5cafe4c2b87451059036438d5c60d6c14fc9a94fd703be7f902b802dfbe2fe2
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -159,7 +159,7 @@ Ruby.
|
|
159
159
|
|
160
160
|
### Calling ruby methods from Delorean
|
161
161
|
|
162
|
-
|
162
|
+
There are two ways of calling ruby code from delorean. First one is to whitelist methods:
|
163
163
|
|
164
164
|
```ruby
|
165
165
|
|
@@ -184,6 +184,35 @@ By default Delorean has some methods whitelisted, such as `length`, `min`, `max`
|
|
184
184
|
|
185
185
|
```
|
186
186
|
|
187
|
+
Another way is to define methods using `delorean_fn` and `cached_delorean_fn`.
|
188
|
+
Use `extend Delorean::Functions` or `include Delorean::Model` in your module or class.
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
class Dummy < ActiveRecord::Base
|
192
|
+
include Delorean::Model
|
193
|
+
|
194
|
+
delorean_fn(:heres_my_number, sig: [0, Float::INFINITY]) do |*a|
|
195
|
+
a.inject(0, :+)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
module DummyModule
|
200
|
+
extend Delorean::Functions
|
201
|
+
|
202
|
+
delorean_fn(:heres_my_number, sig: [0, Float::INFINITY]) do |*a|
|
203
|
+
a.inject(0, :+)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
```
|
207
|
+
|
208
|
+
`heres_my_number` method will be accessible from Delorean code.
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
ExampleScript:
|
212
|
+
a = Dummy.heres_my_number(867, 5309)'
|
213
|
+
b = DummyModule.heres_my_number(867, 5309)'
|
214
|
+
```
|
215
|
+
|
187
216
|
### Caching
|
188
217
|
|
189
218
|
Delorean provides `cached_delorean_function` method that will cache result based on arguments.
|
data/delorean.gemspec
CHANGED
@@ -22,5 +22,6 @@ Gem::Specification.new do |gem|
|
|
22
22
|
gem.add_development_dependency 'pry'
|
23
23
|
gem.add_development_dependency 'rspec', '~> 2.1'
|
24
24
|
gem.add_development_dependency 'rubocop'
|
25
|
+
gem.add_development_dependency 'rubocop-performance'
|
25
26
|
gem.add_development_dependency 'sqlite3', '~> 1.3.10'
|
26
27
|
end
|
data/lib/delorean/base.rb
CHANGED
@@ -162,7 +162,7 @@ module Delorean
|
|
162
162
|
|
163
163
|
# FIXME: this is pretty hacky -- should probably merge
|
164
164
|
# whitelist and SIG mechanisms.
|
165
|
-
if obj.is_a?(Class)
|
165
|
+
if obj.is_a?(Class) || obj.is_a?(Module)
|
166
166
|
_e[:_engine].parse_check_call_fn(method, args.count, obj)
|
167
167
|
return obj.send(msg, *args)
|
168
168
|
end
|
data/lib/delorean/engine.rb
CHANGED
@@ -193,10 +193,9 @@ module Delorean
|
|
193
193
|
err(UndefinedError, "Can't find class: #{class_name}")
|
194
194
|
end
|
195
195
|
|
196
|
-
|
197
|
-
klass.instance_of?(Class)
|
196
|
+
return klass if klass.instance_of?(Class) || klass.instance_of?(Module)
|
198
197
|
|
199
|
-
|
198
|
+
err(UndefinedError, "Access to non-class/module: #{class_name}")
|
200
199
|
end
|
201
200
|
|
202
201
|
def err(exc, msg)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Delorean
|
4
|
+
module Functions
|
5
|
+
def delorean_fn(name, options = {})
|
6
|
+
define_singleton_method(name) do |*args|
|
7
|
+
yield(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
sig = options[:sig]
|
11
|
+
|
12
|
+
raise 'no signature' unless sig
|
13
|
+
|
14
|
+
sig = [sig, sig] if sig.is_a? Integer
|
15
|
+
raise 'Bad signature' unless sig.is_a?(Array) && (sig.length == 2)
|
16
|
+
|
17
|
+
const_set(name.to_s.upcase + Delorean::SIG, sig)
|
18
|
+
end
|
19
|
+
|
20
|
+
# FIXME: IDEA: we just make :cache an argument to delorean_fn.
|
21
|
+
# That way, we don't need the cached_ flavors. It'll make all
|
22
|
+
# this code a lot simpler. We should also just add the :private
|
23
|
+
# mechanism here.
|
24
|
+
|
25
|
+
# By default implements a VERY HACKY class-based (per process) caching
|
26
|
+
# mechanism for database lookup results. Issues include: cached
|
27
|
+
# values are ActiveRecord objects. Query results can be very
|
28
|
+
# large lists which we count as one item in the cache. Caching
|
29
|
+
# mechanism will result in large processes.
|
30
|
+
def cached_delorean_fn(name, options = {})
|
31
|
+
delorean_fn(name, options) do |*args|
|
32
|
+
delorean_cache_adapter = ::Delorean::Cache.adapter
|
33
|
+
# Check if caching should be performed
|
34
|
+
next yield(*args) unless delorean_cache_adapter.cache_item?(
|
35
|
+
klass: self, method_name: name, args: args
|
36
|
+
)
|
37
|
+
|
38
|
+
cache_key = delorean_cache_adapter.cache_key(
|
39
|
+
klass: self, method_name: name, args: args
|
40
|
+
)
|
41
|
+
cached_item = delorean_cache_adapter.fetch_item(
|
42
|
+
klass: self, cache_key: cache_key, default: :NF
|
43
|
+
)
|
44
|
+
|
45
|
+
next cached_item if cached_item != :NF
|
46
|
+
|
47
|
+
res = yield(*args)
|
48
|
+
|
49
|
+
delorean_cache_adapter.cache_item(
|
50
|
+
klass: self, cache_key: cache_key, item: res
|
51
|
+
)
|
52
|
+
|
53
|
+
# Since we're caching this object and don't want anyone
|
54
|
+
# changing it. FIXME: ideally should freeze this object
|
55
|
+
# recursively.
|
56
|
+
res.freeze if res.respond_to?(:freeze)
|
57
|
+
|
58
|
+
res
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def clear_lookup_cache!
|
63
|
+
::Delorean::Cache.adapter.clear!(klass: self)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/delorean/model.rb
CHANGED
@@ -1,76 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'delorean/const'
|
4
|
+
require 'delorean/functions'
|
4
5
|
|
5
6
|
module Delorean
|
6
7
|
module Model
|
7
8
|
def self.included(base)
|
8
|
-
base.send :extend,
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
def delorean_fn(name, options = {})
|
13
|
-
define_singleton_method(name) do |*args|
|
14
|
-
yield(*args)
|
15
|
-
end
|
16
|
-
|
17
|
-
sig = options[:sig]
|
18
|
-
|
19
|
-
raise 'no signature' unless sig
|
20
|
-
|
21
|
-
if sig
|
22
|
-
sig = [sig, sig] if sig.is_a? Integer
|
23
|
-
raise 'Bad signature' unless sig.is_a?(Array) && (sig.length == 2)
|
24
|
-
|
25
|
-
const_set(name.to_s.upcase + Delorean::SIG, sig)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# FIXME: IDEA: we just make :cache an argument to delorean_fn.
|
30
|
-
# That way, we don't need the cached_ flavors. It'll make all
|
31
|
-
# this code a lot simpler. We should also just add the :private
|
32
|
-
# mechanism here.
|
33
|
-
|
34
|
-
# By default implements a VERY HACKY class-based (per process) caching
|
35
|
-
# mechanism for database lookup results. Issues include: cached
|
36
|
-
# values are ActiveRecord objects. Query results can be very
|
37
|
-
# large lists which we count as one item in the cache. Caching
|
38
|
-
# mechanism will result in large processes.
|
39
|
-
def cached_delorean_fn(name, options = {})
|
40
|
-
delorean_fn(name, options) do |*args|
|
41
|
-
delorean_cache_adapter = ::Delorean::Cache.adapter
|
42
|
-
# Check if caching should be performed
|
43
|
-
next yield(*args) unless delorean_cache_adapter.cache_item?(
|
44
|
-
klass: self, method_name: name, args: args
|
45
|
-
)
|
46
|
-
|
47
|
-
cache_key = delorean_cache_adapter.cache_key(
|
48
|
-
klass: self, method_name: name, args: args
|
49
|
-
)
|
50
|
-
cached_item = delorean_cache_adapter.fetch_item(
|
51
|
-
klass: self, cache_key: cache_key, default: :NF
|
52
|
-
)
|
53
|
-
|
54
|
-
next cached_item if cached_item != :NF
|
55
|
-
|
56
|
-
res = yield(*args)
|
57
|
-
|
58
|
-
delorean_cache_adapter.cache_item(
|
59
|
-
klass: self, cache_key: cache_key, item: res
|
60
|
-
)
|
61
|
-
|
62
|
-
# Since we're caching this object and don't want anyone
|
63
|
-
# changing it. FIXME: ideally should freeze this object
|
64
|
-
# recursively.
|
65
|
-
res.freeze if res.respond_to?(:freeze)
|
66
|
-
|
67
|
-
res
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def clear_lookup_cache!
|
72
|
-
::Delorean::Cache.adapter.clear!(klass: self)
|
73
|
-
end
|
9
|
+
base.send :extend, ::Delorean::Functions
|
74
10
|
end
|
75
11
|
end
|
76
12
|
end
|
data/lib/delorean/version.rb
CHANGED
data/lib/delorean_lang.rb
CHANGED
@@ -8,8 +8,10 @@ require 'delorean/base'
|
|
8
8
|
require 'delorean/debug'
|
9
9
|
require 'delorean/delorean'
|
10
10
|
require 'delorean/cache'
|
11
|
+
require 'delorean/const'
|
11
12
|
require 'delorean/engine'
|
12
13
|
require 'delorean/error'
|
14
|
+
require 'delorean/functions'
|
13
15
|
require 'delorean/model'
|
14
16
|
require 'delorean/nodes'
|
15
17
|
require 'delorean/ruby'
|
data/spec/eval_spec.rb
CHANGED
@@ -357,6 +357,20 @@ eoc
|
|
357
357
|
r.should == 867 + 5309
|
358
358
|
end
|
359
359
|
|
360
|
+
it 'should be able to use ruby modules as values and call their methods' do
|
361
|
+
engine.parse defn('A:',
|
362
|
+
' a = DummyModule',
|
363
|
+
' b = a.heres_my_number(867, 5309)',
|
364
|
+
' c = M::DummyModule.heres_my_number(867, 5309)',
|
365
|
+
)
|
366
|
+
# binding.pry
|
367
|
+
r = engine.evaluate('A', 'b')
|
368
|
+
r.should == 867 + 5309
|
369
|
+
|
370
|
+
r = engine.evaluate('A', 'c')
|
371
|
+
r.should == 867 + 5309
|
372
|
+
end
|
373
|
+
|
360
374
|
it 'should ignore undeclared params sent to eval which match attr names' do
|
361
375
|
engine.parse defn('A:',
|
362
376
|
' d = 12',
|
data/spec/spec_helper.rb
CHANGED
@@ -122,6 +122,18 @@ Delorean::Ruby.whitelist.add_method :name2 do |method|
|
|
122
122
|
method.called_on Dummy
|
123
123
|
end
|
124
124
|
|
125
|
+
module DummyModule
|
126
|
+
extend Delorean::Functions
|
127
|
+
|
128
|
+
delorean_fn(:heres_my_number, sig: [0, Float::INFINITY]) do |*a|
|
129
|
+
a.inject(0, :+)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
module M
|
134
|
+
DummyModule = ::DummyModule
|
135
|
+
end
|
136
|
+
|
125
137
|
######################################################################
|
126
138
|
|
127
139
|
class TestContainer < Delorean::AbstractContainer
|
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: 0.5.
|
4
|
+
version: 0.5.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arman Bostani
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-05-
|
11
|
+
date: 2019-05-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop-performance
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: sqlite3
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -123,6 +137,7 @@ files:
|
|
123
137
|
- lib/delorean/delorean.treetop
|
124
138
|
- lib/delorean/engine.rb
|
125
139
|
- lib/delorean/error.rb
|
140
|
+
- lib/delorean/functions.rb
|
126
141
|
- lib/delorean/model.rb
|
127
142
|
- lib/delorean/nodes.rb
|
128
143
|
- lib/delorean/ruby.rb
|