delorean_lang 0.5.3 → 0.5.4

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: abf633643467cfaea17671df87afddee204b361c86df7cd6a83f2a9d5dfec262
4
- data.tar.gz: b6d5544061eb9cd4e1cbe604dbcd2c0f72c746a3ab4aa81837777eece9e87a58
3
+ metadata.gz: afc7142d7683c1fe4d606a86dd7c46eff3ae672b1eb58db13cb587c18b9ea741
4
+ data.tar.gz: a522e77939cbcaa4b8592980ced9281179a07e171fe3e34b69adba13661a8215
5
5
  SHA512:
6
- metadata.gz: d4e00b359a7af226c2006958cbae162377c76ad6edddb575ea36ee3fa1a4db3506814dfdbb1f65d55b7fcc9a84fcf30e3ca6f34ed0f76feff0d3e039b26fe936
7
- data.tar.gz: 2dc5a21daa092f7c50c3a0fa25986f0b6cd49a39eab56ce0483486a9ca0f42726f464727693c908bcb3dd7d406f86141676cb2bb09772299c9636c6bce3389c1
6
+ metadata.gz: 03b53dcf912b0311f12151e6fa189e797f767205cd36d6aac6547d58ab6fad6cfbe6905766caae199c15d4898360829a2249379d61634fec98062fc33753b8ae
7
+ data.tar.gz: d21c189ed7f03b98cc5c21525a1c031b4a6d43477291744a7016e75f411ca9aad5cafe4c2b87451059036438d5c60d6c14fc9a94fd703be7f902b802dfbe2fe2
data/.rubocop.yml CHANGED
@@ -1,3 +1,4 @@
1
+ require: rubocop-performance
1
2
  inherit_from: .rubocop_todo.yml
2
3
 
3
4
  AllCops:
@@ -75,3 +76,5 @@ Style/PerlBackrefs:
75
76
  Naming/HeredocDelimiterCase:
76
77
  Enabled: false
77
78
 
79
+ Naming/RescuedExceptionsVariableName:
80
+ Enabled: false
data/README.md CHANGED
@@ -159,7 +159,7 @@ Ruby.
159
159
 
160
160
  ### Calling ruby methods from Delorean
161
161
 
162
- Ruby methods that are called from Delorean should be whitelisted.
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
@@ -193,10 +193,9 @@ module Delorean
193
193
  err(UndefinedError, "Can't find class: #{class_name}")
194
194
  end
195
195
 
196
- err(UndefinedError, "Access to non-class: #{class_name}") unless
197
- klass.instance_of?(Class)
196
+ return klass if klass.instance_of?(Class) || klass.instance_of?(Module)
198
197
 
199
- klass
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
@@ -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, ClassMethods
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delorean
4
- VERSION = '0.5.3'.freeze
4
+ VERSION = '0.5.4'.freeze
5
5
  end
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.3
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-07 00:00:00.000000000 Z
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