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 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