rVM 0.0.12 → 0.0.13
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.
- data/lib/rvm.rb +2 -2
- data/lib/rvm/acts_as_rvm_type.rb +23 -5
- data/lib/rvm/classes.rb +21 -7
- data/lib/rvm/functions.rb +47 -7
- data/lib/rvm/functions/rails.rb +3 -0
- data/lib/rvm/functions/rails/print.rb +18 -0
- data/lib/rvm/interpreter.rb +358 -62
- data/lib/rvm/languages/ecma.rb +2 -2
- data/lib/rvm/rails.rb +65 -0
- data/spec/languages/ecma/json_spec.rb +137 -14
- metadata +6 -2
data/lib/rvm.rb
CHANGED
data/lib/rvm/acts_as_rvm_type.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
# to the rVM interpreter without going through the hassle of defining each
|
4
4
|
# function on it's own and publisheing every varialbe that is watned.
|
5
5
|
#
|
6
|
+
# The function to call is ActsAsRVMTypeMethods::acts_as_rvm_type.
|
7
|
+
#
|
6
8
|
# == Example
|
7
9
|
# class Test
|
8
10
|
# # Add the readers and writers for
|
@@ -13,7 +15,6 @@
|
|
13
15
|
# register_function :to_s
|
14
16
|
# end
|
15
17
|
|
16
|
-
|
17
18
|
module RVM::ActsAsRVMType
|
18
19
|
|
19
20
|
# Called when included, loads the class methods and the instance methods needed.
|
@@ -61,25 +62,37 @@ module RVM::ActsAsRVMType
|
|
61
62
|
@variables
|
62
63
|
end
|
63
64
|
end
|
65
|
+
|
66
|
+
# Return the variables hash for the firs call.
|
64
67
|
@variables
|
65
68
|
end
|
66
69
|
|
67
70
|
# This function will set up the variables for a rVM and replaces
|
68
71
|
# the current function with a shorter and faster one.
|
69
72
|
def functions
|
73
|
+
# Copy the original functions hash so that changes to the instance
|
74
|
+
# wont't carry over to to other instances.
|
70
75
|
@functions = self.class.object_functions.dup
|
76
|
+
|
77
|
+
# Redefine the function method to speed up further accesses.
|
71
78
|
instance_eval do
|
72
79
|
def functions
|
73
80
|
@functions
|
74
81
|
end
|
75
82
|
end
|
76
|
-
|
83
|
+
|
84
|
+
# Return the functions hash for the first call.
|
85
|
+
@functions
|
77
86
|
end
|
78
|
-
|
79
87
|
end
|
80
88
|
|
89
|
+
|
90
|
+
# This module hods the instance methods for classes that are supposed to
|
91
|
+
# act as a rVM type.
|
92
|
+
#
|
93
|
+
# It includes +register_variable+ and +register_function+ to help setting up
|
94
|
+
# the class quickly.
|
81
95
|
module ActsAsRVMTypeInstanceMethods
|
82
|
-
|
83
96
|
# This registers a variable for the rVM interface, it allows the scripts
|
84
97
|
# to read and write them. If +writable+ is set this will be a read only
|
85
98
|
# variable. It alls an be published to rVM under a different name,
|
@@ -92,7 +105,7 @@ module RVM::ActsAsRVMType
|
|
92
105
|
# to read and write them. If +writable+ is set this will be a read only
|
93
106
|
# variable. It alls an be published to rVM under a different name,
|
94
107
|
# by passing +published_as+.
|
95
|
-
def register_function name, published_as =
|
108
|
+
def register_function name, published_as = name
|
96
109
|
@functions[published_as.to_s] = Class.new(RVM::Functions::Function) do @name = name; end
|
97
110
|
class << @functions[published_as.to_s]
|
98
111
|
def execute params, env
|
@@ -105,9 +118,14 @@ module RVM::ActsAsRVMType
|
|
105
118
|
end
|
106
119
|
end
|
107
120
|
|
121
|
+
# Returns the hash of variables for to be used only internally by the
|
122
|
+
# ActsAsRVMTypeSingeltonMethods#variables function to set up the details.
|
108
123
|
def object_variables
|
109
124
|
@variables
|
110
125
|
end
|
126
|
+
|
127
|
+
# Returns the hash of variables for to be used only internally by the
|
128
|
+
# ActsAsRVMTypeSingeltonMethods#variables function to set up the details.
|
111
129
|
def object_functions
|
112
130
|
@functions
|
113
131
|
end
|
data/lib/rvm/classes.rb
CHANGED
@@ -47,18 +47,29 @@ module RVM
|
|
47
47
|
# end
|
48
48
|
class Class
|
49
49
|
|
50
|
+
# We make classes a Plugin and set the plugin host to Classes s it can
|
51
|
+
# handle the details for it.
|
50
52
|
extend RVM::Plugin
|
51
53
|
plugin_host Classes
|
52
54
|
|
53
|
-
|
55
|
+
# Basic functions hash for classes so every class at least can respond
|
56
|
+
# to a +functions+ call.
|
54
57
|
def functions
|
55
58
|
@functions ||= {}
|
56
59
|
end
|
57
60
|
|
61
|
+
# Basic variables hash for classes so every class at least can respond
|
62
|
+
# to a +variables+ call.
|
58
63
|
def variables
|
59
|
-
@variables ||= {
|
64
|
+
@variables ||= {}
|
60
65
|
end
|
61
66
|
|
67
|
+
|
68
|
+
# Every class is by default treated as beeing true when not defined
|
69
|
+
# otherwise.
|
70
|
+
# This makes sure that calling boolean functions on classes will always
|
71
|
+
# return a usefull result.
|
72
|
+
# So it can be redefinde to say, have 0 act as false if this is wanted.
|
62
73
|
def is_true?
|
63
74
|
true
|
64
75
|
end
|
@@ -77,17 +88,20 @@ module RVM
|
|
77
88
|
true
|
78
89
|
end
|
79
90
|
|
80
|
-
|
81
|
-
|
91
|
+
# Redefinding the method to allow using self defined functions
|
92
|
+
# within classes - while this is discuraged it still is possible.
|
82
93
|
def method_missing(m, *args, &block)
|
94
|
+
# Check if the functions PluginHost knwos about the called function
|
83
95
|
if (RVM::Functions::has? m)
|
84
|
-
|
96
|
+
# Calls the function with given args and enviroment that is,
|
97
|
+
# hopefully defiend in the calling class.
|
98
|
+
RVM::Functions[m].execute args, @env
|
85
99
|
else
|
100
|
+
# If the function is not known we call the usual method missing
|
101
|
+
# method.
|
86
102
|
super(m, *args, &block)
|
87
|
-
#method_missing_old_class m, *args, &block
|
88
103
|
end
|
89
104
|
end
|
90
|
-
|
91
105
|
end
|
92
106
|
end
|
93
107
|
end
|
data/lib/rvm/functions.rb
CHANGED
@@ -1,25 +1,39 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/plugin'
|
2
2
|
require File.dirname(__FILE__) + '/interpreter'
|
3
3
|
module RVM
|
4
|
-
|
4
|
+
# This module holds all the functions laded for the rVM to to keep them
|
5
|
+
# organized and handle which are accassabel and which not.
|
5
6
|
module Functions
|
6
7
|
extend RVM::PluginHost
|
8
|
+
|
9
|
+
# Basic Parent for every function defined, it registers it to the
|
10
|
+
# PluginHost and sets up some basic functionality.
|
11
|
+
# Just parent a class to this and define +execute+ as a class function
|
12
|
+
# and it can be handled.
|
7
13
|
class Function
|
14
|
+
|
15
|
+
# Registers this as plugin and sets up the PluginHost
|
8
16
|
extend RVM::Plugin
|
9
17
|
plugin_host Functions
|
18
|
+
|
10
19
|
class << self
|
11
|
-
|
20
|
+
# By default every function should have a universal return value,
|
21
|
+
# this make sure it is not refused if it isn't defined correctly.
|
12
22
|
def data_type
|
13
23
|
:any
|
14
24
|
end
|
15
25
|
|
16
|
-
|
17
|
-
|
26
|
+
# We want to allow functions to call other functions without going
|
27
|
+
# through explic calls.
|
28
|
+
# Again it isn't exactly encuraged but possible if needed to.
|
18
29
|
def method_missing(m, *args, &block)
|
30
|
+
# First we check if a function with the name given is defined vor rVM
|
19
31
|
if (RVM::Functions::has? m)
|
32
|
+
# if so we call it with the given arguments
|
20
33
|
RVM::Functions[m].execute args, @env
|
21
34
|
else
|
22
|
-
|
35
|
+
# If not we let ruby do it's magic.
|
36
|
+
super(m, *args, &block)
|
23
37
|
end
|
24
38
|
end
|
25
39
|
|
@@ -29,25 +43,51 @@ module RVM
|
|
29
43
|
true
|
30
44
|
end
|
31
45
|
|
46
|
+
|
47
|
+
# Call is used to call the function it handles translating the passed
|
48
|
+
# parameters to the correct types or throw a exception if RVM::strict
|
49
|
+
# is set.
|
50
|
+
# This is what you want if you call a function to ensure all parameters
|
51
|
+
# are passed correctly.
|
32
52
|
def call params, env, pos = nil
|
33
53
|
i = 0
|
54
|
+
# We want to make sure that if we don't have signatures from the
|
55
|
+
# function we have a default signature of any to prevent automatic
|
56
|
+
# type castng in that case
|
34
57
|
sig = :any
|
35
58
|
params.map! do |p|
|
59
|
+
# We try to get the next signature if we don't have any further we
|
60
|
+
# take the last one used so [:number, :number, :number] behaves the
|
61
|
+
# same as just [:number] as it will be repeated
|
36
62
|
sig = signature[i] || sig
|
63
|
+
# Now we check if the expected type is not ':any' nor the current
|
64
|
+
# argument has the right type.
|
37
65
|
if sig != :any and p.class != RVM::Classes[sig]
|
38
|
-
|
66
|
+
# Okay if we have RVM::strict set we don't allow auto type
|
67
|
+
# casting so we throw a Exception
|
68
|
+
raise "TYPE MISMATCH! expected #{sig} got #{p.class}(#{pos.join(':')}) at " if RVM::strict
|
69
|
+
# Otherwise we try to typecast the parameter.
|
39
70
|
p = RVM::Classes[sig].new(p)
|
40
71
|
end
|
72
|
+
# Go to the next parameter in the list
|
41
73
|
i+=1
|
74
|
+
# and make sure the former one is replaced (value of the block)
|
42
75
|
p
|
43
76
|
end if not signature.empty?
|
77
|
+
# Now we execute the function code and cache the esult
|
44
78
|
r = execute(params, env)
|
79
|
+
# print a debug message if needed
|
45
80
|
RVM::debug "#{self.inspect}: #{signature.inspect} = '#{r}'" if $DEBUG
|
46
81
|
r
|
47
82
|
end
|
48
83
|
|
84
|
+
|
85
|
+
# This executes the function code and returns the result.
|
86
|
+
#
|
87
|
+
# It must be implemented for every function used otherwise it will
|
88
|
+
# end up without doing anything.
|
49
89
|
def execute params, env
|
50
|
-
|
90
|
+
RVM::Classes[:error].new(1,"Function code for #{self} not implemented.")
|
51
91
|
end
|
52
92
|
end
|
53
93
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RVM
|
2
|
+
module Functions
|
3
|
+
class Print < RVM::Functions::Function
|
4
|
+
class << self
|
5
|
+
def execute params, env
|
6
|
+
params.each do |p|
|
7
|
+
env.read_var_val(:render) << p.to_s
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def signature
|
12
|
+
[:any]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
register_for :print
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/rvm/interpreter.rb
CHANGED
@@ -1,22 +1,40 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/functions'
|
2
2
|
require File.dirname(__FILE__) + '/classes'
|
3
3
|
module RVM
|
4
|
-
# This Module hold all the VM
|
5
|
-
#
|
4
|
+
# This Module hold all the VM classes that are used to execute and evaluate
|
5
|
+
# code for the VM, so it is quite important to read and understand if you
|
6
|
+
# feel like making a own compiler.
|
6
7
|
#
|
7
|
-
#
|
8
|
-
#
|
8
|
+
# For someone not interested in going as deep into building a own compiler
|
9
|
+
# it still is a good start for understanding how rVM works, yet it is not
|
10
|
+
# mandatory to read.
|
11
|
+
#
|
12
|
+
# The basic idea of this objects is that the compiler translates the source
|
13
|
+
# code into a tree of RVM::Interpreter objects to build the behavior that is
|
14
|
+
# expected. Once that is done the code can be executed by calling #execute
|
15
|
+
# for the root of the object tree.
|
9
16
|
#
|
10
17
|
module Interpreter
|
11
18
|
|
12
19
|
|
20
|
+
# Helper class to be parented to other Interpreter calsses for checks and
|
21
|
+
# including general behavior.
|
13
22
|
class Element
|
23
|
+
# The position in the soruce code, added to help debugging scripts with
|
24
|
+
# problems.
|
14
25
|
attr_accessor :pos
|
26
|
+
|
27
|
+
# Initializes the interpreter element with a position.
|
15
28
|
def initialize pos
|
16
29
|
@pos = pos
|
17
30
|
end
|
18
31
|
end
|
32
|
+
|
19
33
|
# This is a helper fuctio to quickly generate a empty enviorment.
|
34
|
+
# A hash can be passed to store variables.
|
35
|
+
#
|
36
|
+
# :locals can be a hash holding local variables
|
37
|
+
# :functions can be a hash to hold functions defined in the the scope
|
20
38
|
def Interpreter.env aenv = {}
|
21
39
|
RVM::debug "Interpreter.env" if $DEBUG
|
22
40
|
Enviroment.new aenv
|
@@ -29,16 +47,28 @@ module RVM
|
|
29
47
|
RVM::Interpreter::Constant.new(RVM::Classes[type].new(value), pos)
|
30
48
|
end
|
31
49
|
|
32
|
-
# This class is used to store the variable content to allow chross
|
33
|
-
# and passing variables upwards through different scopes.
|
50
|
+
# This class is used to store the variable content to allow chross
|
51
|
+
# refferencing and passing variables upwards through different scopes.
|
34
52
|
class VariableStorage
|
35
|
-
|
36
|
-
|
53
|
+
|
54
|
+
# Lets the script read the value of the variable.
|
55
|
+
attr_reader :val
|
56
|
+
|
57
|
+
# The storage is initialized with two optional parameters:
|
58
|
+
#
|
59
|
+
# +val+:: which is the value to be stores.
|
60
|
+
# +writable+:: which when set to false prevents the variable to be
|
61
|
+
# written, which might be helpfull when trying to publish
|
62
|
+
# some data to a script that is not supposed to be changed.
|
63
|
+
def initialize val = nil, writable = true
|
37
64
|
@writable = writable
|
38
65
|
@val = val
|
39
|
-
instance_eval(&block) if block
|
40
66
|
end
|
41
67
|
|
68
|
+
# Used to write to the variable, if +writable+ was set to false this
|
69
|
+
# will have no effect.
|
70
|
+
#
|
71
|
+
# It returns the new value set or, if +writable+ was false the old value.
|
42
72
|
def val=v
|
43
73
|
@val = v if @writable
|
44
74
|
@val
|
@@ -47,16 +77,37 @@ module RVM
|
|
47
77
|
|
48
78
|
# The callback storang is used to help publishing variables from a ruby
|
49
79
|
# class to the rVM, it will get and set the variables during runtime.
|
80
|
+
#
|
81
|
+
# It will link getter and setter methods and not the instance variable
|
82
|
+
# itself, which means also computed attributes can be handled by this.
|
83
|
+
#
|
84
|
+
# This class is made if it is nessessary that a script always has access
|
85
|
+
# to constantly chaning data within a object and not only deal with static
|
86
|
+
# values set once.
|
50
87
|
class VariableStorageCallback < VariableStorage
|
88
|
+
# The construtor takes 3 parameters to specifie the object it shold
|
89
|
+
# be linked with, the attribute to handle and +writable+ that will define
|
90
|
+
# if the VariableStorage can be written too by the script.
|
91
|
+
#
|
92
|
+
# var is expected to by a Symbol equal the the function, the getter will
|
93
|
+
# call obj.var and the setter will call obj.var=.
|
94
|
+
#
|
51
95
|
def initialize obj, var, writable = true
|
52
96
|
super(nil, writable)
|
53
97
|
@obj = obj
|
54
98
|
@get = var.to_sym
|
55
99
|
@set = "#{var}=".to_sym
|
56
100
|
end
|
101
|
+
|
102
|
+
# This methods sets the variable passed to the object by sending it to
|
103
|
+
# the setter method.
|
57
104
|
def val= v
|
58
105
|
@obj.send(@set,v) if @writable
|
106
|
+
@obj.send(@get)
|
59
107
|
end
|
108
|
+
|
109
|
+
# The getter will call the getter of the object to handle to get the
|
110
|
+
# current value.
|
60
111
|
def val
|
61
112
|
@obj.send(@get)
|
62
113
|
end
|
@@ -71,10 +122,17 @@ module RVM
|
|
71
122
|
# for example function calls.
|
72
123
|
class Enviroment
|
73
124
|
# This creates a new enviroment enviroment, it generates a new env
|
74
|
-
# default variables are set if not defined in
|
125
|
+
# default variables are set if not defined in +data+.
|
75
126
|
#
|
76
|
-
# If
|
127
|
+
# If +oldenv+ is provided it will also fall back to see if not
|
77
128
|
# existing variables
|
129
|
+
#
|
130
|
+
# +init_data+ is a hash that can be passed the following values:
|
131
|
+
# :locals:: A hash with local variables mapped name => value
|
132
|
+
# :functions:: A hash with functions for the scope.
|
133
|
+
# :evaldeepth:: A fixnum that indicates how deep the evaluation is.
|
134
|
+
# :params:: A array that holds local parameters for example for functions
|
135
|
+
# or blocks.
|
78
136
|
def initialize init_data = {}, oldenv=nil
|
79
137
|
|
80
138
|
@data = {
|
@@ -84,22 +142,33 @@ module RVM
|
|
84
142
|
:params => []
|
85
143
|
}.merge(init_data)
|
86
144
|
|
87
|
-
|
145
|
+
|
146
|
+
# Make sure that all locals that are passed, are actually in a variable
|
147
|
+
# storage.
|
88
148
|
if init_data[:locals]
|
149
|
+
# For easy access we get us a link to the locals
|
89
150
|
locals = @data[:locals]
|
151
|
+
# Now we itterate through them
|
90
152
|
init_data[:locals].each do |k,v|
|
153
|
+
#For every variable that isn't already in a storage
|
91
154
|
if not v.is_a?(VariableStorage)
|
155
|
+
# We put it in a storage to assure the enviroment is propper.
|
92
156
|
locals[k] = VariableStorage.new(v)
|
93
157
|
end
|
94
158
|
end
|
95
159
|
end
|
96
160
|
|
161
|
+
# We store the priviouse enviroment to look upwards through the scopes
|
162
|
+
# for priviouse defined variables, if no old enviroment was given we
|
163
|
+
# set the priviose scope to an empty hash.
|
97
164
|
@prev = oldenv || {}
|
98
165
|
RVM::debug "data: #{data}\noldenv:#{oldenv}" if $DEBUG
|
99
|
-
RVM::debug "Creating new enviroment with: #{@data.inspect} as child
|
166
|
+
RVM::debug "Creating new enviroment with: #{@data.inspect} as child" +
|
167
|
+
" of #{@prev}" if $DEBUG
|
100
168
|
end
|
101
169
|
|
102
|
-
#
|
170
|
+
# Allows raw access to the data, it should not be used unless
|
171
|
+
# somoene knows pretty exactly what they are doing.
|
103
172
|
def data
|
104
173
|
@data
|
105
174
|
end
|
@@ -131,47 +200,67 @@ module RVM
|
|
131
200
|
#
|
132
201
|
# If the variable exists in a 'higher' enviroment the value is changed.
|
133
202
|
#
|
134
|
-
# If not it is newly created in the current enviroment and thus not
|
135
|
-
# in upper enviroments.
|
136
|
-
def []=
|
137
|
-
|
138
|
-
|
139
|
-
if
|
140
|
-
|
203
|
+
# If not it is newly created in the current enviroment and thus not
|
204
|
+
# visible in upper enviroments.
|
205
|
+
def []= name, value
|
206
|
+
RVM::debug "Setting variable #{name} to #{value}" if $DEBUG
|
207
|
+
# First we try to get the variable storage of the variable requested.
|
208
|
+
# This will work if it was defined in this or a priviouse scope.
|
209
|
+
if (res = self[name])
|
210
|
+
# If we found the storage we'll change it's value and not define it
|
211
|
+
# again.
|
212
|
+
res.val = value
|
141
213
|
else
|
142
|
-
|
214
|
+
# If we didn't found a Variable storage, the variable wasn't defined
|
215
|
+
# before so we make a new VariableStorage and save the variable in
|
216
|
+
# it.
|
217
|
+
@data[:locals][name] = VariableStorage.new(value)
|
143
218
|
end
|
144
|
-
|
219
|
+
value
|
145
220
|
end
|
221
|
+
|
146
222
|
# Defines a varialbe in the current scope, priviose variables are not
|
147
|
-
# changed
|
148
|
-
|
149
|
-
|
223
|
+
# changed.
|
224
|
+
# This is needed for local varialbe declarations that overwrite priviouse
|
225
|
+
# globals.
|
226
|
+
def declare name, value
|
227
|
+
@data[:locals][name] = VariableStorage.new(value)
|
150
228
|
end
|
151
229
|
|
152
|
-
# Returns a function for the current enviroment
|
230
|
+
# Returns a function for the enviroment. If the current enviroment does
|
231
|
+
# not hold a function with the requested name it checks through the
|
232
|
+
# entire tree if a function can be found in the outer scopes.
|
233
|
+
#
|
153
234
|
# The result is to be execpted to be of the +RVM::Classes::Block+ class.
|
154
|
-
def function
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
RVM::debug "Getting functon #{
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
235
|
+
def function name
|
236
|
+
# Try to get the function in the local defintions.
|
237
|
+
fun = @data[:functions][name]
|
238
|
+
# if that fails and we have a previous enviroment check that
|
239
|
+
fun = @prev.function(name) if fun.nil? and @prev.is_a? Enviroment
|
240
|
+
RVM::debug "Getting functon #{name} (#{fun})" if $DEBUG
|
241
|
+
# return what was found
|
242
|
+
fun
|
243
|
+
end
|
244
|
+
|
245
|
+
# This defines a function within the enviroment and lets you call it later
|
246
|
+
# on.
|
164
247
|
#
|
165
|
-
# It
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
248
|
+
# It expects the body to be a RVM::Classes::Block so it can be executed.
|
249
|
+
# The return value is the given block
|
250
|
+
def def_function name, body
|
251
|
+
if not body.is_a?(RVM::Classes::Block)
|
252
|
+
raise(ArgumentError, "Function definitions must be of block class.")
|
253
|
+
end
|
254
|
+
@data[:functions][name] = body
|
255
|
+
RVM::debug "Setting functon #{name} (#{body})" if $DEBUG
|
256
|
+
body
|
171
257
|
end
|
172
258
|
|
173
|
-
# This functin is closely related to +[]+ with the difference that it
|
174
|
-
#
|
259
|
+
# This functin is closely related to +[]+ with the difference that it
|
260
|
+
# returns the value and not the VariableStorage object.
|
261
|
+
# It is equivalent to [].val just that it also deals with nil ojects and
|
262
|
+
# and returns a RVM::Classes::Error if the requested variable wasn't
|
263
|
+
# found.
|
175
264
|
def read_var_val name
|
176
265
|
|
177
266
|
r = nil
|
@@ -186,19 +275,38 @@ module RVM
|
|
186
275
|
end
|
187
276
|
|
188
277
|
|
189
|
-
#
|
278
|
+
# Jumps into object context (anther way beside using send).
|
190
279
|
#
|
191
|
-
#
|
280
|
+
# The special variable :self (attention, not to be mixed wiht 'self')
|
192
281
|
# is set to the object in which context we are!
|
193
282
|
#
|
194
|
-
#
|
283
|
+
# This is one of the few RVM::Interpreter calsses that is likely to be used
|
284
|
+
# outside a compiler as it will allow to execute a set of code within the
|
285
|
+
# scope of a specific object:
|
286
|
+
#
|
287
|
+
# =Example
|
288
|
+
# RVM::Interpreter::ObjectContext.new(my_object, my_code).execute(env)
|
289
|
+
#
|
290
|
+
# This will execute my_code in a way pretty much equal to instance_eval in
|
291
|
+
# ruby would do.
|
195
292
|
class ObjectContext < Element
|
293
|
+
|
294
|
+
# The constructor takes 3 arguments, the first beeing the object of which
|
295
|
+
# the scope is taken, the second is the code to be executed in the objects
|
296
|
+
# scope and the third is the position, to be set by the compiler.
|
297
|
+
#
|
298
|
+
# The passed object is executed once when the code is ran so it can be
|
299
|
+
# passed something that evaluates like a variable, or constant.
|
196
300
|
def initialize object, code, pos = nil
|
197
301
|
super(pos)
|
198
302
|
@object = object
|
199
303
|
@code = code
|
200
304
|
end
|
201
305
|
|
306
|
+
# Execute for this Interpreter element by creating a new enviroment,
|
307
|
+
# setting it's variables and functions to those definded by the object's
|
308
|
+
# +functions+ and +variables+ methods. It also sets the :self variable in
|
309
|
+
# the new enviroment to the object.
|
202
310
|
def execute env
|
203
311
|
#The new
|
204
312
|
obj = @object.execute(env)
|
@@ -209,9 +317,14 @@ module RVM
|
|
209
317
|
end
|
210
318
|
|
211
319
|
|
212
|
-
#This sets a funciton on a Class (to be included in its objects)
|
320
|
+
# This sets a funciton on a Class (to be included in its objects)
|
213
321
|
#
|
214
|
-
#To define class functions use ObjectContext and define the function
|
322
|
+
# To define class functions use ObjectContext and define the function
|
323
|
+
# normaly, nifty isn't it?
|
324
|
+
#
|
325
|
+
# This object may be subject to removal or change, don't use it yet.
|
326
|
+
#---
|
327
|
+
# TODO: Work this over.
|
215
328
|
class SetClassFunction < Element
|
216
329
|
def initialize obj, name, function, pos = nil
|
217
330
|
super(pos)
|
@@ -247,8 +360,10 @@ module RVM
|
|
247
360
|
end
|
248
361
|
end
|
249
362
|
|
250
|
-
|
251
|
-
#
|
363
|
+
|
364
|
+
# The FunctionDefinition can be used to define functions in the current
|
365
|
+
# scope, it can either be methods belonging to a object when called within
|
366
|
+
# object scope or good old functions.
|
252
367
|
class FunctionDefinition < Element
|
253
368
|
|
254
369
|
# Initializes a new function definition
|
@@ -263,6 +378,9 @@ module RVM
|
|
263
378
|
# override:: when true (default) earlyer definitions are
|
264
379
|
# replaced when it is called a second time.
|
265
380
|
# When false a exception is thrown
|
381
|
+
#
|
382
|
+
# pos:: The position within the source code of the definition - for
|
383
|
+
# deugging purpose.
|
266
384
|
def initialize name, body, override = true, pos = nil
|
267
385
|
super(pos)
|
268
386
|
@name = name
|
@@ -270,6 +388,12 @@ module RVM
|
|
270
388
|
@override = override
|
271
389
|
end
|
272
390
|
|
391
|
+
# When executed the FunctionDefinition first checks if a function with the
|
392
|
+
# same name is already defined. If it is and +override+ wasn't set to ture
|
393
|
+
# it trows a Exception. Otherwise it defines the function, deleting the
|
394
|
+
# old definition when still repsent.
|
395
|
+
#
|
396
|
+
# It returns the body of the newly defined function.
|
273
397
|
def execute env
|
274
398
|
if (not @override) and env.function(@name)
|
275
399
|
raise "Function #{@name} already defined at #{@pos}!"
|
@@ -282,19 +406,31 @@ module RVM
|
|
282
406
|
|
283
407
|
# This is a loop. It is executed over and over again as long as
|
284
408
|
# the passed condition evaluates to a value that matches is_true?.
|
409
|
+
#
|
410
|
+
#---
|
411
|
+
#TODO: Add BreakException to stop execution of loops.
|
412
|
+
#TODO: Add NextExceeption to skip rest of a evaluation on loop code.
|
285
413
|
class Loop < Element
|
286
414
|
# Initializes a new loop.
|
287
415
|
#
|
288
416
|
# condition:: is executed before each run of the loop. If it evaluates
|
289
417
|
# to true the loop is executed another time otherwise the
|
290
418
|
# exection ends.
|
419
|
+
#
|
291
420
|
# body:: For each itteration of the loop this is executed once.
|
421
|
+
#
|
422
|
+
# pos:: The position within the source code of the definition - for
|
423
|
+
# deugging purpose.
|
292
424
|
def initialize(condition, body, pos = nil)
|
293
425
|
super(pos)
|
294
426
|
@condition = condition
|
295
427
|
@body = body
|
296
428
|
end
|
297
429
|
|
430
|
+
# The loop will execute as long as the code passed as condition evaluates
|
431
|
+
# to is_true?.
|
432
|
+
# Once the loop stops executing the return value is the result of the last
|
433
|
+
# body execution.
|
298
434
|
def execute env
|
299
435
|
r = nil
|
300
436
|
while @condition.execute(env).is_true?
|
@@ -315,18 +451,25 @@ module RVM
|
|
315
451
|
@value = value
|
316
452
|
end
|
317
453
|
|
454
|
+
# A constat returns the data type of the value that is stored in it.
|
318
455
|
def data_type
|
319
456
|
@value.data_type
|
320
457
|
end
|
321
458
|
|
459
|
+
# Comparing a constant with something has two ways to go, if the object
|
460
|
+
# it is compared to is a Constant the two values are compared. If not the
|
461
|
+
# Constant compares the value with the passed object.
|
322
462
|
def == v
|
323
463
|
if v.is_a? Constant
|
324
464
|
@value == v.value
|
325
465
|
else
|
466
|
+
@value == v
|
326
467
|
false
|
327
468
|
end
|
328
469
|
end
|
329
470
|
|
471
|
+
# When executed the constant returns the value stored in it, without
|
472
|
+
# evaluating it.
|
330
473
|
def execute env
|
331
474
|
RVM::debug "Executing Constant at #{@pos}: #{@value}" if $DEBUG
|
332
475
|
@value
|
@@ -358,10 +501,15 @@ module RVM
|
|
358
501
|
# Creates a new condition with the given parameters. The false_case can
|
359
502
|
# be ommitted.
|
360
503
|
#
|
361
|
-
#
|
362
|
-
#
|
363
|
-
#
|
364
|
-
#
|
504
|
+
# value:: is executed, and depandant of the result either true_case or
|
505
|
+
# false casae s executed.
|
506
|
+
#
|
507
|
+
# true_case:: is only executed if value evalutes to true (is_true?)
|
508
|
+
#
|
509
|
+
# false_case:: is only executed if value evalutes to false (!is_true?)
|
510
|
+
#
|
511
|
+
# pos:: The position within the source code of the definition - for
|
512
|
+
# deugging purpose.
|
365
513
|
def initialize value, true_case, false_case = nil, pos = nil
|
366
514
|
super(pos)
|
367
515
|
@value = value
|
@@ -369,6 +517,11 @@ module RVM
|
|
369
517
|
@false_case = false_case
|
370
518
|
end
|
371
519
|
|
520
|
+
|
521
|
+
# The data type of a condition is tried to evaluate by checking if the
|
522
|
+
# type is the same for both conditions, if so the common type is returned,
|
523
|
+
# if not :any is returend as it can not be determined what type the
|
524
|
+
# Condition will have.
|
372
525
|
def data_type
|
373
526
|
if @true_case.data_type == @false_case.data_type
|
374
527
|
@false_case.data_type
|
@@ -377,6 +530,12 @@ module RVM
|
|
377
530
|
end
|
378
531
|
end
|
379
532
|
|
533
|
+
# When executed the condition first executes the condition, if it
|
534
|
+
# evaluates to a value that .is_true? the true case is executed if not,
|
535
|
+
# and a false case is given it will be executed.
|
536
|
+
#
|
537
|
+
# The return value is the value of the executed condition, so either the
|
538
|
+
# ture_case or the false_case.
|
380
539
|
def execute env
|
381
540
|
v = @value.execute(env)
|
382
541
|
if v and v.is_true?
|
@@ -389,22 +548,44 @@ module RVM
|
|
389
548
|
end
|
390
549
|
end
|
391
550
|
|
392
|
-
|
393
|
-
#
|
551
|
+
|
552
|
+
# A variable assignment that sets a local variable. A declaration
|
553
|
+
# is not required before the assignment can be done, yet it can be used to
|
554
|
+
# force a laready declaed variale into the local scope.
|
394
555
|
#
|
395
|
-
# Both the
|
556
|
+
# Both the +name+ and the +value+ are evaluated before the assignment
|
396
557
|
# is done.
|
397
558
|
class Assignment < Element
|
559
|
+
|
560
|
+
# A Assignment is initialized wiht 2 to 3 parameters.
|
561
|
+
#
|
562
|
+
# name:: The name of the variable to store, it will be executed, usually
|
563
|
+
# this will be a Constant, unless dynamic naming is needed by the
|
564
|
+
# implemented language.
|
565
|
+
#
|
566
|
+
# value:: The value that will be assigned to the variable, for a = 1 + 1
|
567
|
+
# '1+1' would be the value to assign, so as this already suggests
|
568
|
+
# the value will be executed.
|
569
|
+
#
|
570
|
+
# pos:: The position within the source code of the definition - for
|
571
|
+
# deugging purpose.
|
398
572
|
def initialize name, value, pos = nil
|
399
573
|
super(pos)
|
400
574
|
@name = name
|
401
575
|
@value = value
|
402
576
|
end
|
403
577
|
|
578
|
+
# The data type of a Assignment is the data type of it's value.
|
404
579
|
def data_type
|
405
580
|
@value.data_type
|
406
581
|
end
|
407
582
|
|
583
|
+
# When executed the assignment first evaluates the name of the assignment
|
584
|
+
# then the value and stores the result of the executed value in the
|
585
|
+
# enviroment under the name of the executed name.
|
586
|
+
#
|
587
|
+
# The return value of the execution is the value that is assigned to the
|
588
|
+
# variable.
|
408
589
|
def execute env
|
409
590
|
RVM::debug "Executing Assignment at #{@pos}..." if $DEBUG
|
410
591
|
env[@name.execute(env).to_s] = @value.execute env
|
@@ -414,19 +595,45 @@ module RVM
|
|
414
595
|
# A variable declarion that sets a local variable, it will redelcare
|
415
596
|
# the variable if declared in a privouse scope.
|
416
597
|
#
|
417
|
-
#
|
598
|
+
# It is very closely related to the Assignment as it acts exactly alike if
|
599
|
+
# the variable is not yet existing in the Enviroment.
|
600
|
+
#
|
601
|
+
# Both the +name+ and the #value# are evaluated before the assignment
|
418
602
|
# is done.
|
419
603
|
class Declaration < Element
|
604
|
+
# A Declaration is initialized wiht 2 to 3 parameters.
|
605
|
+
#
|
606
|
+
# name:: The name of the variable to store, it will be executed, usually
|
607
|
+
# this will be a Constant, unless dynamic naming is needed by the
|
608
|
+
# implemented language.
|
609
|
+
#
|
610
|
+
# value:: The value that will be assigned to the variable, for a = 1 + 1
|
611
|
+
# '1+1' would be the value to assign, so as this already suggests
|
612
|
+
# the value will be executed.
|
613
|
+
#
|
614
|
+
# pos:: The position within the source code of the definition - for
|
615
|
+
# deugging purpose.
|
420
616
|
def initialize name, value, pos = nil
|
421
617
|
super(pos)
|
422
618
|
@name = name
|
423
619
|
@value = value
|
424
620
|
end
|
425
621
|
|
622
|
+
# The data type of a Assignment is the data type of it's value.
|
426
623
|
def data_type
|
427
624
|
@value.data_type
|
428
625
|
end
|
429
626
|
|
627
|
+
# When executed the assignment first evaluates the name of the assignment
|
628
|
+
# then the value and stores the result of the executed value in the
|
629
|
+
# enviroment under the name of the executed name.
|
630
|
+
#
|
631
|
+
# If the variable was priviosely in a enviroment that lays above the
|
632
|
+
# current one in the hearachy the old value will not be altered in any
|
633
|
+
# way but a new variable declared.
|
634
|
+
#
|
635
|
+
# The return value of the execution is the value that is assigned to the
|
636
|
+
# variable.
|
430
637
|
def execute env
|
431
638
|
RVM::debug "Executing Assignment at #{@pos}..." if $DEBUG
|
432
639
|
env.declare(@name.execute(env).to_s,@value.execute(env)).val
|
@@ -435,8 +642,15 @@ module RVM
|
|
435
642
|
|
436
643
|
# Reads the value of a variable in the enviroment.
|
437
644
|
#
|
438
|
-
# The
|
645
|
+
# The +name+ is evaluated before the variable is retrieved.
|
439
646
|
class Variable < Element
|
647
|
+
# A Variable is initialized wiht 1 to 2 parameters.
|
648
|
+
#
|
649
|
+
# name:: The name of the variable to get, it will be executed as long as
|
650
|
+
# it is no Sybol in which case it is treated as a special variable.
|
651
|
+
#
|
652
|
+
# pos:: The position within the source code of the definition - for
|
653
|
+
# deugging purpose.
|
440
654
|
def initialize name, pos = nil
|
441
655
|
super(pos)
|
442
656
|
@name = name
|
@@ -449,6 +663,10 @@ module RVM
|
|
449
663
|
@type
|
450
664
|
end
|
451
665
|
|
666
|
+
# When the name is a symbol, the name isn't executed and treated as a
|
667
|
+
# special variable.
|
668
|
+
# Otherwise the name is executed and converted into a string to be passed
|
669
|
+
# to the enviroment so it can go and collect the value.
|
452
670
|
def execute env
|
453
671
|
RVM::debug "Executing Variable at #{@pos}..." if $DEBUG
|
454
672
|
n = @name
|
@@ -464,6 +682,14 @@ module RVM
|
|
464
682
|
# This evauates to the parameter passed to the function call.
|
465
683
|
# The number of it is evaluated and typecasted to an interger.
|
466
684
|
class Parameter < Element
|
685
|
+
|
686
|
+
# A Parameter is initialized wiht 1 to 2 parameters.
|
687
|
+
#
|
688
|
+
# num:: The number if the parameter to get, 0 is the first parameter
|
689
|
+
# passed, 1 the second and so on.
|
690
|
+
#
|
691
|
+
# pos:: The position within the source code of the definition - for
|
692
|
+
# deugging purpose.
|
467
693
|
def initialize num, pos = nil
|
468
694
|
super(pos)
|
469
695
|
@num = num
|
@@ -476,6 +702,11 @@ module RVM
|
|
476
702
|
@type
|
477
703
|
end
|
478
704
|
|
705
|
+
# When executed the Parameter evaluates the number, of the parameter and
|
706
|
+
# then queries the enviroment to get the function parameter requested.
|
707
|
+
#
|
708
|
+
# After the first execution the parameter remembers the type of the value
|
709
|
+
# it returns.
|
479
710
|
def execute env
|
480
711
|
RVM::debug "Executing Parameter at #{@pos}..." if $DEBUG
|
481
712
|
r = env.param(@num.execute(env).to_i)
|
@@ -489,10 +720,23 @@ module RVM
|
|
489
720
|
# The type of the squence is equal to the last element of the sequence.
|
490
721
|
class Sequence < Array
|
491
722
|
attr_accessor :pos
|
723
|
+
|
724
|
+
# The Sequence is initialized wiht 1 to 2 parameters.
|
725
|
+
#
|
726
|
+
# src:: The source is an array that holds the inital list of commands that
|
727
|
+
# are supposed to be executed.
|
728
|
+
#
|
729
|
+
# pos:: The position within the source code of the definition - for
|
730
|
+
# deugging purpose.
|
492
731
|
def initialize src=[], pos = nil
|
493
732
|
super(src)
|
494
733
|
@pos = pos
|
495
734
|
end
|
735
|
+
|
736
|
+
# When exeuted a sequence starts to execute every element in it starting
|
737
|
+
# with the first element in the array.
|
738
|
+
#
|
739
|
+
# The result is the last element of the array executed.
|
496
740
|
def execute env
|
497
741
|
RVM::debug "Executing Sequence... #{inspect}" if $DEBUG
|
498
742
|
r = nil
|
@@ -502,10 +746,14 @@ module RVM
|
|
502
746
|
r
|
503
747
|
end
|
504
748
|
|
749
|
+
# When adding something to the Sequence a new Sequence will be created
|
750
|
+
# with the result of the joined arrays.
|
505
751
|
def + v
|
506
752
|
Sequence.new(super)
|
507
753
|
end
|
508
754
|
|
755
|
+
# The data type of the list is :any as it is unknown where the the
|
756
|
+
# sequence exits.
|
509
757
|
def data_type
|
510
758
|
:any
|
511
759
|
end
|
@@ -518,6 +766,13 @@ module RVM
|
|
518
766
|
class ReturnException < Exception
|
519
767
|
attr_reader :val
|
520
768
|
attr_reader :pos
|
769
|
+
|
770
|
+
# The ReturnException is initialized wiht 1 to 2 parameters.
|
771
|
+
#
|
772
|
+
# val:: The value that will be returned, aka the part after 'return'.
|
773
|
+
#
|
774
|
+
# pos:: The position within the source code of the definition - for
|
775
|
+
# deugging purpose.
|
521
776
|
def initialize val, pos = nil
|
522
777
|
super()
|
523
778
|
@val = val
|
@@ -529,15 +784,26 @@ module RVM
|
|
529
784
|
# +ReturnException+ which can be caught to have the function
|
530
785
|
# or block return what they wish.
|
531
786
|
class Return < Element
|
787
|
+
|
788
|
+
# The Return is initialized wiht 1 to 2 parameters.
|
789
|
+
#
|
790
|
+
# val:: The value that will be returned, aka the part after 'return'.
|
791
|
+
#
|
792
|
+
# pos:: The position within the source code of the definition - for
|
793
|
+
# deugging purpose.
|
532
794
|
def initialize val, pos = nil
|
533
795
|
super(pos)
|
534
796
|
@val = val
|
535
797
|
end
|
536
798
|
|
799
|
+
# The data type of a return statement is any, as it does not return
|
800
|
+
# anything at all, after all it jumps out of a block.
|
537
801
|
def data_type
|
538
802
|
:any
|
539
803
|
end
|
540
804
|
|
805
|
+
# When executed the Return executed the value and then raises a
|
806
|
+
# ReturnException.
|
541
807
|
def execute env
|
542
808
|
raise ReturnException.new(@val.execute(env))
|
543
809
|
end
|
@@ -552,7 +818,7 @@ module RVM
|
|
552
818
|
class FunctionCall < Element
|
553
819
|
attr_reader :arguments
|
554
820
|
attr_reader :function
|
555
|
-
# The constructor.
|
821
|
+
# The constructor. +function+ can either be a block object or a function
|
556
822
|
# class.
|
557
823
|
#
|
558
824
|
# Arguments is a list of the arguments to the function.
|
@@ -562,10 +828,14 @@ module RVM
|
|
562
828
|
@arguments = arguments
|
563
829
|
end
|
564
830
|
|
831
|
+
# The data type of the FunctionCall is the return value of the function
|
832
|
+
# that it calls.
|
565
833
|
def data_type
|
566
834
|
@function.data_type
|
567
835
|
end
|
568
836
|
|
837
|
+
# Comparing two function calls will result in a match when the passed
|
838
|
+
# arguments are the same and the function to call the same
|
569
839
|
def == v
|
570
840
|
if v.is_a? FunctionCall
|
571
841
|
(@arguments == v.arguments) && (@function == v.function)
|
@@ -574,26 +844,52 @@ module RVM
|
|
574
844
|
end
|
575
845
|
end
|
576
846
|
|
847
|
+
# When executed the FunctionCall has four possible behaviours.
|
848
|
+
#
|
849
|
+
# 1) If the function is a block, so an anonymous function, the arguments
|
850
|
+
# will be executed and then the block is called.
|
851
|
+
#
|
852
|
+
# 2) The function is a locally defined function and then the arguments are
|
853
|
+
# executed and passed to the locally defined function.
|
854
|
+
#
|
855
|
+
# 3) The function is a RVM::Functions::Function and execargs returns true,
|
856
|
+
# the arguments are executed and the function called.
|
857
|
+
#
|
858
|
+
# 4) The function is a RVM::Functions::Function and execargs returns
|
859
|
+
# false, the arguments are passed along unexecuted and the function has
|
860
|
+
# to take care of that itself. This is important for logical functions
|
861
|
+
# as and and or which execute only some of the arguments
|
577
862
|
def execute env
|
578
863
|
RVM::debug "Executing FunctionCall..." if $DEBUG
|
579
864
|
args = @arguments.dup
|
865
|
+
# The function is a anonymous function
|
580
866
|
if @function.is_a? RVM::Classes[:block]
|
867
|
+
# The arguments are executed.
|
581
868
|
args.map! do |arg|
|
582
869
|
arg.execute env
|
583
870
|
end
|
871
|
+
# Call the function
|
584
872
|
@function.call(args, env, @pos)
|
873
|
+
# The function is a selfdefined function (or object function)
|
585
874
|
elsif fun = env.function(@function)
|
875
|
+
# The arguments are executed.
|
586
876
|
args.map! do |arg|
|
587
877
|
arg.execute env
|
588
878
|
end
|
879
|
+
# Call the function
|
589
880
|
fun.call(args, env, @pos)
|
881
|
+
# If nothing of the above the function must be a global function.
|
590
882
|
else
|
883
|
+
# Get the function from he globals
|
591
884
|
fun = RVM::Functions[@function]
|
885
|
+
# Test if the arguments should be executed
|
592
886
|
if fun.execargs
|
887
|
+
# The arges get executed
|
593
888
|
args.map! do |arg|
|
594
889
|
arg.execute env
|
595
890
|
end
|
596
891
|
end
|
892
|
+
# Call the function
|
597
893
|
fun.call(args, env, @pos)
|
598
894
|
end
|
599
895
|
end
|
data/lib/rvm/languages/ecma.rb
CHANGED
@@ -53,7 +53,7 @@ module_eval(<<'...end ecma.y/module_eval...', 'ecma.y', 219)
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
@q.push [:STRING, [m, [line, s.pos - pos]]]
|
56
|
-
elsif s.scan(/(
|
56
|
+
elsif s.scan(/(\.\d+|(0(\.\d+)?)|([1-9](\d*(\.\d+)?)))(e[+-]?\d+)?/i)
|
57
57
|
@q.push [:NUMBER, [s.matched, [line, s.pos - pos]]]
|
58
58
|
elsif s.scan(/\[/)
|
59
59
|
@q.push [:SBRACKET_OPEN, [s.matched, [line, s.pos - pos]]]
|
@@ -99,7 +99,7 @@ module_eval(<<'...end ecma.y/module_eval...', 'ecma.y', 219)
|
|
99
99
|
@q.push [m, [m, [line, s.pos - pos]]]
|
100
100
|
elsif s.scan(/\s+/)
|
101
101
|
else
|
102
|
-
raise "Woops! I can daeal with char at #{line}:#{s.pos - pos}: #{s.pre_match} #{s.post_match}"
|
102
|
+
raise Exception, "Woops! I can daeal with char at #{line}:#{s.pos - pos}: #{s.pre_match} #{s.post_match}"
|
103
103
|
end
|
104
104
|
end
|
105
105
|
@q.push([false, '$end'])
|
data/lib/rvm/rails.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.dirname(__FILE__) +'/acts_as_rvm_type.rb'
|
2
|
+
|
3
|
+
# Inlcude the RVM::ACtsAsRVMType into active record so functions like
|
4
|
+
# +acts_as_rvm_type+ and comparable
|
5
|
+
ActiveRecord::Base.class_eval do
|
6
|
+
include RVM::ActsAsRVMType
|
7
|
+
end
|
8
|
+
|
9
|
+
class ActionView::Base
|
10
|
+
|
11
|
+
# This function allows to render code that gets compiled by rvm. The first
|
12
|
+
# parameter passed is the code to compile, a string most likely, the second
|
13
|
+
# is a hash that is passed to the render function, see the Rails API doc for
|
14
|
+
# details on what to put there.
|
15
|
+
#
|
16
|
+
# In addition to those rails specifc parameters rvm_render accepts 4 additioal
|
17
|
+
# parameters.They are the same as used in +rvm_execute+.
|
18
|
+
def rvm_reder code, options = {}
|
19
|
+
render options.merge({:text => rvm_execute(code, options)})
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
# The rvm_execute executes a string of code with a certein behavior and
|
24
|
+
# returns not the result but what was written in the special :render variable
|
25
|
+
# of the enviroment.
|
26
|
+
#
|
27
|
+
# The folowing options can be passed to it to influence it's behaviro.
|
28
|
+
#
|
29
|
+
# :language:: The language that should be used to compile the code, be adwised
|
30
|
+
# that it is nessessary to load this prior to executing it.
|
31
|
+
#
|
32
|
+
# :enviroment:: This allows to pass a own enviroment, for example to publish
|
33
|
+
# variables or to maintain state between executions.
|
34
|
+
#
|
35
|
+
# :object:: If this is set the code will be executed in the context of the
|
36
|
+
# object passed, this using it's local variable storage and it's
|
37
|
+
# functions. Be aware that when using :object and :enviroment
|
38
|
+
# togehter, variables set in the code will NOT go in the enviroment
|
39
|
+
# as they are local in the object.
|
40
|
+
#
|
41
|
+
# :timeout:: This is used to limit the execution time of the code, it can be
|
42
|
+
# used to prevent runaway processes beeing executed. Very helpfull
|
43
|
+
# when the code executed isn't 100% trunstworty.
|
44
|
+
def rvm_execute code, options = {}
|
45
|
+
options = {
|
46
|
+
:language => :ecma,
|
47
|
+
:enviroment => RVM::Interpreter.env
|
48
|
+
}.merge(options)
|
49
|
+
compiler = RVM::Languages[options[:language]].new
|
50
|
+
code = compiler.compile(code)
|
51
|
+
code = RVM::Interpreter::ObjectContext.new(options[:object], code) if options[:object]
|
52
|
+
if options[:enviroment][:render].is_a? RVM::Classes::Error or options[:enviroment][:render].nil?
|
53
|
+
options[:enviroment][:render] = ""
|
54
|
+
end
|
55
|
+
puts options[:enviroment][:render].inspect
|
56
|
+
if options[:timeout]
|
57
|
+
s = RVM::Safety.new :timeout => options[:timeout]
|
58
|
+
s.execute(code, options[:enviroment])
|
59
|
+
else
|
60
|
+
code.execute(options[:enviroment])
|
61
|
+
end
|
62
|
+
options[:enviroment][:render].val
|
63
|
+
end
|
64
|
+
end
|
65
|
+
require File.dirname(__FILE__) + '/functions/rails.rb'
|
@@ -12,21 +12,144 @@ describe RVM::Languages::ECMA do
|
|
12
12
|
@compiler = RVM::Languages::ECMA.new
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
describe "positives" do
|
16
|
+
it "should compile the first json example" do
|
17
|
+
lambda {
|
18
|
+
exec File.new(File.dirname(__FILE__) + '/json/pass1.json').read
|
19
|
+
}.should_not raise_error
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should compile the second json example" do
|
23
|
+
lambda {
|
24
|
+
exec File.new(File.dirname(__FILE__) + '/json/pass2.json').read
|
25
|
+
}.should_not raise_error
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should compile the third json example" do
|
29
|
+
lambda {
|
30
|
+
exec File.new(File.dirname(__FILE__) + '/json/pass3.json').read
|
31
|
+
}.should_not raise_error
|
32
|
+
end
|
19
33
|
end
|
20
34
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
35
|
+
describe "negatives" do
|
36
|
+
it "should fail the 2nd negative example" do
|
37
|
+
lambda {
|
38
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail2.json').read
|
39
|
+
}.should raise_error
|
40
|
+
end
|
41
|
+
it "should fail the 4th negative example" do
|
42
|
+
lambda {
|
43
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail4.json').read
|
44
|
+
}.should raise_error
|
45
|
+
end
|
46
|
+
it "should fail the 5th negative example" do
|
47
|
+
lambda {
|
48
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail5.json').read
|
49
|
+
}.should raise_error
|
50
|
+
end
|
51
|
+
it "should fail the 6th negative example" do
|
52
|
+
lambda {
|
53
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail6.json').read
|
54
|
+
}.should raise_error
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should fail the 7th negative example" do
|
58
|
+
lambda {
|
59
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail7.json').read
|
60
|
+
}.should raise_error
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should fail the 8th negative example" do
|
64
|
+
lambda {
|
65
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail8.json').read
|
66
|
+
}.should raise_error
|
67
|
+
end
|
68
|
+
it "should fail the 9th negative example" do
|
69
|
+
lambda {
|
70
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail9.json').read
|
71
|
+
}.should raise_error
|
72
|
+
end
|
73
|
+
it "should fail the 10th negative example" do
|
74
|
+
lambda {
|
75
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail10.json').read
|
76
|
+
}.should raise_error
|
77
|
+
end
|
78
|
+
it "should fail the 12th negative example" do
|
79
|
+
lambda {
|
80
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail12.json').read
|
81
|
+
}.should raise_error
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should fail the 13th negative example" do
|
85
|
+
lambda {
|
86
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail13.json').read
|
87
|
+
}.should raise_error
|
88
|
+
end
|
89
|
+
it "should fail the 14th negative example" do
|
90
|
+
lambda {
|
91
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail14.json').read
|
92
|
+
}.should raise_error
|
93
|
+
end
|
94
|
+
it "should fail the 15th negative example" do
|
95
|
+
lambda {
|
96
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail15.json').read
|
97
|
+
}.should raise_error
|
98
|
+
end
|
99
|
+
it "should fail the 16th negative example" do
|
100
|
+
lambda {
|
101
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail16.json').read
|
102
|
+
}.should raise_error
|
103
|
+
end
|
104
|
+
it "should fail the 17th negative example" do
|
105
|
+
lambda {
|
106
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail17.json').read
|
107
|
+
}.should raise_error
|
108
|
+
end
|
109
|
+
it "should fail the 19th negative example" do
|
110
|
+
lambda {
|
111
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail19.json').read
|
112
|
+
}.should raise_error
|
113
|
+
end
|
114
|
+
it "should fail the 20th negative example" do
|
115
|
+
lambda {
|
116
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail20.json').read
|
117
|
+
}.should raise_error
|
118
|
+
end
|
119
|
+
it "should fail the 21th negative example" do
|
120
|
+
lambda {
|
121
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail21.json').read
|
122
|
+
}.should raise_error
|
123
|
+
end
|
124
|
+
it "should fail the 22th negative example" do
|
125
|
+
lambda {
|
126
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail22.json').read
|
127
|
+
}.should raise_error
|
128
|
+
end
|
129
|
+
it "should fail the 29th negative example" do
|
130
|
+
lambda {
|
131
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail29.json').read
|
132
|
+
}.should raise_error
|
133
|
+
end
|
134
|
+
it "should fail the 30th negative example" do
|
135
|
+
lambda {
|
136
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail30.json').read
|
137
|
+
}.should raise_error
|
138
|
+
end
|
139
|
+
it "should fail the 31th negative example" do
|
140
|
+
lambda {
|
141
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail31.json').read
|
142
|
+
}.should raise_error
|
143
|
+
end
|
144
|
+
it "should fail the 32th negative example" do
|
145
|
+
lambda {
|
146
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail32.json').read
|
147
|
+
}.should raise_error
|
148
|
+
end
|
149
|
+
it "should fail the 33th negative example" do
|
150
|
+
lambda {
|
151
|
+
exec File.new(File.dirname(__FILE__) + '/json/fail33.json').read
|
152
|
+
}.should raise_error
|
153
|
+
end
|
31
154
|
end
|
32
155
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rVM
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Heinz N. Gies
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-07-
|
12
|
+
date: 2008-07-29 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -85,6 +85,9 @@ files:
|
|
85
85
|
- lib/rvm/functions/math.rb
|
86
86
|
- lib/rvm/functions/objects
|
87
87
|
- lib/rvm/functions/objects/send.rb
|
88
|
+
- lib/rvm/functions/rails
|
89
|
+
- lib/rvm/functions/rails/print.rb
|
90
|
+
- lib/rvm/functions/rails.rb
|
88
91
|
- lib/rvm/functions/string
|
89
92
|
- lib/rvm/functions/string/ansi.rb
|
90
93
|
- lib/rvm/functions/string/capstr.rb
|
@@ -107,6 +110,7 @@ files:
|
|
107
110
|
- lib/rvm/languages.rb
|
108
111
|
- lib/rvm/library.rb
|
109
112
|
- lib/rvm/plugin.rb
|
113
|
+
- lib/rvm/rails.rb
|
110
114
|
- lib/rvm.rb
|
111
115
|
- README
|
112
116
|
has_rdoc: true
|