r_bridge 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +20 -3
- data/ext/r_bridge/r_lang.c +16 -1
- data/lib/r_bridge/r_bridge_ffi.rb +38 -3
- data/lib/r_bridge/r_bridge_lazyfunc_ext.rb +81 -15
- data/lib/r_bridge/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee29073e5090bf0ac44de5a81374aad07050f0518ea7bd0c3942d4d7ce523487
|
4
|
+
data.tar.gz: b93811a27fb58066cd93660009c0a9555cf7e74380727149e9f8a353ccb8893d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce3cbb9fd43d040599d88e3f49512917b9981f268816c5f82ae2e0722d86e33e3934ae5dacf796e0c467bdd6ff08001b33f2c25cb97d594698adbe895a199344
|
7
|
+
data.tar.gz: b850ea4e23d9a5b504c94ca761640a9e3e8f34bb08b79809b6e563d0457ac9b9f31257b1817e3eb4c47cb66ec8862c2acbc928ced2a0c901bb445cad656b613b
|
data/README.md
CHANGED
@@ -216,11 +216,13 @@ RBridge.create_extptr( ffi_ptr )
|
|
216
216
|
|
217
217
|
* Create R function call
|
218
218
|
|
219
|
-
create_function_call
|
219
|
+
create_ns_function_call, create_env_function_call and create_function_call create R's internal S expresion structures for function calls. create_ns_function_call can specify (package) namespace. create_env_function_call can specify environment name.
|
220
220
|
|
221
|
-
Arguments are passed
|
221
|
+
Arguments are passed as Ruby Hash, and each Hash's value needs to point to R's object. You usually pass R vectors, but you can also pass another function call as an argument.
|
222
222
|
|
223
223
|
```
|
224
|
+
RBridge.create_ns_function_call( ns, fname, hash )
|
225
|
+
RBridge.create_env_function_call( env, fname, hash )
|
224
226
|
RBridge.create_function_call( fname, hash )
|
225
227
|
|
226
228
|
(e.g.)
|
@@ -231,6 +233,21 @@ RBridge.exec_function_no_return(hellowrold)
|
|
231
233
|
# pass another function call to argument
|
232
234
|
getwd = RBridge.create_function_call( "print", { "x" => RBridge.create_function_call( "getwd", {} ) } )
|
233
235
|
RBridge.exec_function_no_return(getwd)
|
236
|
+
|
237
|
+
# call sqrt function in base package.
|
238
|
+
ivec = RBridge.create_intvec([1,2,3])
|
239
|
+
calc = RBridge.create_ns_function_call( "base","sqrt", {"x" => ivec} )
|
240
|
+
RBridge.exec_function_no_return( RBridge.create_function_call( "print", {"" => calc} )) # execute & print out
|
241
|
+
|
242
|
+
# Call function in environment
|
243
|
+
#
|
244
|
+
# (e.g.) source the following newenv.R and call the newenv$hello function.
|
245
|
+
# # newenv.R
|
246
|
+
# newenv = new.env()
|
247
|
+
# newenv$hello = function(){ print("Hello!") }
|
248
|
+
#
|
249
|
+
RBridge.exec_function_no_return( RBridge.create_function_call("source", { "" => RBridge.create_strvec(["newenv.R"]) }))
|
250
|
+
RBridge.exec_function_no_return( RBridge.create_env_function_call("newenv", "hello", { } ))
|
234
251
|
```
|
235
252
|
|
236
253
|
The followings are utility functions. assign() and library() are frequently used in R, and easy ways to create them are provided.
|
@@ -356,7 +373,7 @@ RBridge.end_embedded_r()
|
|
356
373
|
|
357
374
|
## Additional Features
|
358
375
|
|
359
|
-
* LazyFunc + RParamManager (+ RResultManager): In contrast to create_function_call(),
|
376
|
+
* LazyFunc + RParamManager (+ RResultManager): In contrast to create_function_call(), create_lazy_function(), which creates LazyFunc object, does not need to take existent R objects. It can take RParamName, RResultName and so on, which are not associated with R objects until the function is evaluated. create_ns_lazy_function(), create_env_lazy_function() are lazy evaluation version of create_ns_function_call() and create_env_function_call(), which respectively allows specifying namespaces and environments.
|
360
377
|
|
361
378
|
These features are being developed for StatSailr, and the API is not stable. They can be accessed but they are not recommended for general usage.
|
362
379
|
|
data/ext/r_bridge/r_lang.c
CHANGED
@@ -4,6 +4,22 @@
|
|
4
4
|
|
5
5
|
#include "win_compat.h"
|
6
6
|
|
7
|
+
EXPORT SEXP
|
8
|
+
r_lang_create_ns_fcall( const char* ns, const char* fname, SEXP args)
|
9
|
+
{
|
10
|
+
SEXP func;
|
11
|
+
PROTECT( func = LCONS( LCONS( Rf_install("::"), LCONS( Rf_install(ns), LCONS( Rf_install(fname), R_NilValue))) , args ));
|
12
|
+
return func;
|
13
|
+
}
|
14
|
+
|
15
|
+
EXPORT SEXP
|
16
|
+
r_lang_create_env_fcall( const char* env, const char* fname, SEXP args)
|
17
|
+
{
|
18
|
+
SEXP func;
|
19
|
+
PROTECT( func = LCONS( LCONS( Rf_install("$"), LCONS( Rf_install(env), LCONS( Rf_install(fname), R_NilValue))) , args ));
|
20
|
+
return func;
|
21
|
+
}
|
22
|
+
|
7
23
|
EXPORT SEXP
|
8
24
|
r_lang_create_fcall( const char* fname, SEXP args)
|
9
25
|
{
|
@@ -12,7 +28,6 @@ r_lang_create_fcall( const char* fname, SEXP args)
|
|
12
28
|
return func;
|
13
29
|
}
|
14
30
|
|
15
|
-
|
16
31
|
EXPORT SEXP
|
17
32
|
r_lang_cons( SEXP car, SEXP cdr)
|
18
33
|
{
|
@@ -24,6 +24,8 @@ module RBridge
|
|
24
24
|
attach_function :r_list_to_dataframe, [:pointer ], :pointer
|
25
25
|
attach_function :r_dataframe_set_rownames, [:pointer, :pointer], :void
|
26
26
|
|
27
|
+
attach_function :r_lang_create_ns_fcall, [:string, :string, :pointer], :pointer
|
28
|
+
attach_function :r_lang_create_env_fcall, [:string, :string, :pointer], :pointer
|
27
29
|
attach_function :r_lang_create_fcall, [:string, :pointer], :pointer
|
28
30
|
attach_function :r_lang_cons, [:pointer, :pointer], :pointer
|
29
31
|
attach_function :r_lang_cons_gen, [:pointer], :pointer
|
@@ -272,6 +274,10 @@ module RBridge
|
|
272
274
|
return new_lcons
|
273
275
|
end
|
274
276
|
|
277
|
+
def self.r_nil()
|
278
|
+
return r_lang_nil()
|
279
|
+
end
|
280
|
+
|
275
281
|
def self.is_r_nil?( obj )
|
276
282
|
result = r_is_nil( obj )
|
277
283
|
if(result == 1)
|
@@ -294,9 +300,8 @@ module RBridge
|
|
294
300
|
return extptr
|
295
301
|
end
|
296
302
|
|
297
|
-
def self.
|
298
|
-
raise "
|
299
|
-
raise "create_function_call should take Hash for function arguments" if(hash.class != Hash)
|
303
|
+
def self.hash_to_lcons_args( hash )
|
304
|
+
raise "hash_to_lcons_args should take Hash argument" if(hash.class != Hash)
|
300
305
|
if(hash.size == 0)
|
301
306
|
lcons_args = r_lang_nil()
|
302
307
|
elsif(hash.size == 1)
|
@@ -322,6 +327,36 @@ module RBridge
|
|
322
327
|
idx = idx + 1
|
323
328
|
}
|
324
329
|
end
|
330
|
+
return lcons_args
|
331
|
+
end
|
332
|
+
|
333
|
+
def self.create_ns_function_call( ns, fname, hash )
|
334
|
+
raise "create_ns_function_call should take String for namespace" if(ns.class != String)
|
335
|
+
raise "create_ns_function_call should take String for function name" if(fname.class != String)
|
336
|
+
raise "create_ns_function_call should take Hash for function arguments" if(hash.class != Hash)
|
337
|
+
lcons_args = hash_to_lcons_args( hash )
|
338
|
+
|
339
|
+
new_function_call = r_lang_create_ns_fcall(ns, fname, lcons_args)
|
340
|
+
ptr_manager_add_ptr_to_current( new_function_call )
|
341
|
+
return new_function_call
|
342
|
+
end
|
343
|
+
|
344
|
+
def self.create_env_function_call( env, fname, hash )
|
345
|
+
raise "create_env_function_call should take String for env" if(env.class != String)
|
346
|
+
raise "create_env_function_call should take String for function name" if(fname.class != String)
|
347
|
+
raise "create_env_function_call should take Hash for function arguments" if(hash.class != Hash)
|
348
|
+
lcons_args = hash_to_lcons_args( hash )
|
349
|
+
|
350
|
+
new_function_call = r_lang_create_env_fcall(env, fname, lcons_args)
|
351
|
+
ptr_manager_add_ptr_to_current( new_function_call )
|
352
|
+
return new_function_call
|
353
|
+
end
|
354
|
+
|
355
|
+
def self.create_function_call( fname, hash )
|
356
|
+
raise "create_function_call should take String for function name" if(fname.class != String)
|
357
|
+
raise "create_function_call should take Hash for function arguments" if(hash.class != Hash)
|
358
|
+
lcons_args = hash_to_lcons_args( hash )
|
359
|
+
|
325
360
|
new_function_call = r_lang_create_fcall(fname, lcons_args)
|
326
361
|
ptr_manager_add_ptr_to_current( new_function_call )
|
327
362
|
return new_function_call
|
@@ -1,21 +1,46 @@
|
|
1
1
|
require "r_bridge/r_bridge_ffi"
|
2
2
|
|
3
3
|
module RBridge
|
4
|
+
def self.create_ns_lazy_function( ns, fname, hash , param_manager)
|
5
|
+
raise "create_ns_lazy_function should take String for namespace" if(ns.class != String)
|
6
|
+
raise "create_ns_lazy_function should take String for function name" if(fname.class != String)
|
7
|
+
raise "create_ns_lazy_function should take Hash for function arguments" if(hash.class != Hash)
|
8
|
+
return LazyFunc.new( ns, nil, fname, hash , param_manager)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.create_env_lazy_function( env, fname, hash , param_manager)
|
12
|
+
raise "create_env_lazy_function should take String for environment" if(env.class != String)
|
13
|
+
raise "create_env_lazy_function should take String for function name" if(fname.class != String)
|
14
|
+
raise "create_env_lazy_function should take Hash for function arguments" if(hash.class != Hash)
|
15
|
+
return LazyFunc.new( nil, env, fname, hash , param_manager)
|
16
|
+
end
|
17
|
+
|
4
18
|
def self.create_lazy_function( fname, hash , param_manager)
|
5
19
|
raise "create_lazy_function should take String for function name" if(fname.class != String)
|
6
20
|
raise "create_lazy_function should take Hash for function arguments" if(hash.class != Hash)
|
7
|
-
return LazyFunc.new( fname, hash , param_manager)
|
21
|
+
return LazyFunc.new( nil, nil, fname, hash , param_manager)
|
8
22
|
end
|
9
23
|
|
10
|
-
def self.
|
24
|
+
def self.create_function_call_from_lazy_function_attrs( ns, env, fname, fargs, param_manager, result_manager)
|
11
25
|
farg_keys = fargs.keys
|
12
26
|
|
13
27
|
new_arg_hash = {}
|
14
28
|
farg_keys.each(){|key|
|
15
29
|
val = fargs[key]
|
30
|
+
|
31
|
+
if val.is_a? RResultPrevious
|
32
|
+
r_previous = result_manager.get_previous() # if r_nil (i.e. 1st instruction or no previous result-store instructions) we need to use default one.
|
33
|
+
if ! RBridge::is_r_nil?(r_previous) # When previous result exists
|
34
|
+
new_arg_hash[key] = r_previous
|
35
|
+
break
|
36
|
+
else # When previous result does not exist
|
37
|
+
val = val.default
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
16
41
|
case val
|
17
42
|
when LazyFunc then
|
18
|
-
new_arg_hash[key] =
|
43
|
+
new_arg_hash[key] = create_function_call_from_lazy_function_attrs( val.ns, val.env, val.fname, val.args , param_manager, result_manager )
|
19
44
|
when RResultName , RResultNameArray then
|
20
45
|
new_arg_hash[key] = result_manager.get_last_for( val )
|
21
46
|
when RParamName then
|
@@ -27,13 +52,13 @@ module RBridge
|
|
27
52
|
case elem
|
28
53
|
when RResultName, RResultNameArray then
|
29
54
|
result = result_manager.get_last_for( elem )
|
30
|
-
if( ! result
|
55
|
+
if( ! RBridge::is_r_nil?(result) )
|
31
56
|
new_arg_hash[key] = result
|
32
57
|
break
|
33
58
|
end
|
34
59
|
when RParamName then
|
35
60
|
result = param_manager.get_r_object( elem )
|
36
|
-
if( ! result
|
61
|
+
if( ! RBridge::is_r_nil?(result) )
|
37
62
|
new_arg_hash[key] = result
|
38
63
|
break
|
39
64
|
end
|
@@ -44,34 +69,52 @@ module RBridge
|
|
44
69
|
idx = idx + 1
|
45
70
|
end
|
46
71
|
if(idx == val.elems.size ) # Not found
|
47
|
-
new_arg_hash[key] =
|
72
|
+
new_arg_hash[key] = RBridge::r_nil()
|
48
73
|
end
|
49
74
|
else # R object
|
50
75
|
new_arg_hash[key] = val
|
51
76
|
end
|
52
77
|
}
|
53
|
-
|
78
|
+
if( ns.nil? )
|
79
|
+
if( env.nil? )
|
80
|
+
return create_function_call( fname, new_arg_hash )
|
81
|
+
else
|
82
|
+
return create_env_function_call( env, fname, new_arg_hash )
|
83
|
+
end
|
84
|
+
else
|
85
|
+
if( env.nil? )
|
86
|
+
return create_ns_function_call( ns, fname, new_arg_hash )
|
87
|
+
else
|
88
|
+
raise "namespace and environment are not allowed to be specified at the same time."
|
89
|
+
end
|
90
|
+
end
|
54
91
|
end
|
55
92
|
|
56
93
|
def self.exec_lazy_function( lazy_func , result_manager , allow_nil_result: false )
|
57
94
|
raise "exec_lazy_function should take LazyFunc object" if(lazy_func.class != LazyFunc)
|
58
95
|
raise "exec_lazy_function should take RResultManager or Nil for 2nd argment: " + result_manager.class.to_s if(! [RResultManager, NilClass].include?(result_manager.class) )
|
96
|
+
ns = lazy_func.ns
|
97
|
+
env = lazy_func.env
|
59
98
|
fname = lazy_func.fname
|
60
99
|
arg_hash = lazy_func.args
|
61
100
|
param_manager = lazy_func.param_manager
|
62
101
|
|
63
|
-
func =
|
102
|
+
func = create_function_call_from_lazy_function_attrs(ns, env, fname, arg_hash, param_manager, result_manager)
|
64
103
|
result = exec_function( func , allow_nil_result: allow_nil_result )
|
65
104
|
return result
|
66
105
|
end
|
67
106
|
|
68
107
|
class LazyFunc
|
108
|
+
attr :ns
|
109
|
+
attr :env
|
69
110
|
attr :fname
|
70
111
|
attr :args
|
71
112
|
attr :param_manager
|
72
113
|
|
73
|
-
def initialize( fname, arg_hash, param_manager)
|
114
|
+
def initialize( ns, env, fname, arg_hash, param_manager)
|
74
115
|
raise "LazyFunc requires RParamManager object for param_manager argument " if ! param_manager.is_a?(RParamManager)
|
116
|
+
@ns = ns # When namespace does not need to be specified, set nil.
|
117
|
+
@env = env # When environment does not need to be specified, set nil.
|
75
118
|
@fname = fname
|
76
119
|
@args = arg_hash
|
77
120
|
@param_manager = param_manager
|
@@ -86,6 +129,7 @@ module RBridge
|
|
86
129
|
end
|
87
130
|
|
88
131
|
class RParamManager
|
132
|
+
attr :param_hash , true
|
89
133
|
def initialize(hash)
|
90
134
|
@param_hash = hash
|
91
135
|
end
|
@@ -112,6 +156,18 @@ module RBridge
|
|
112
156
|
end
|
113
157
|
end
|
114
158
|
|
159
|
+
class RResultPrevious
|
160
|
+
# RResultPrevious is used for result from the previous instruction.
|
161
|
+
# If the instruction is the 1st one, there are no previous ones. At this time, default one is used.
|
162
|
+
attr :default
|
163
|
+
def initialize(val)
|
164
|
+
if ! ( val.is_a?(RNameContainer) || val.is_a?(RResultName) || val.is_a?(RResultNameArray) || val.is_a?(RParamName) || ::RBridge.is_pointer?( val ) )
|
165
|
+
raise "RResultPrevious.new requires RNameContainer, RResultName, RResultNameArray, RParamName or R object as default"
|
166
|
+
end
|
167
|
+
@default = val
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
115
171
|
class RResultManager
|
116
172
|
def initialize
|
117
173
|
@results = []
|
@@ -125,7 +181,7 @@ module RBridge
|
|
125
181
|
@results << [inst_name, r_obj ]
|
126
182
|
end
|
127
183
|
|
128
|
-
def get_last_index_for( result_name )
|
184
|
+
def get_last_index_for( result_name ) # From this method, if result name is not found return (Ruby) nil.
|
129
185
|
name = result_name.name
|
130
186
|
|
131
187
|
idx = @results.size - 1
|
@@ -143,18 +199,18 @@ module RBridge
|
|
143
199
|
end
|
144
200
|
end
|
145
201
|
|
146
|
-
def get_last_for( r_result ) # If corresponding result name is not found, return
|
202
|
+
def get_last_for( r_result ) # If corresponding result name is not found, return r_nil().
|
147
203
|
raise "get_last_for method requires RResultName or RResultNameArray for its argument." if ! ( r_result.is_a?(RResultName) || r_result.is_a?(RResultNameArray) )
|
148
204
|
if( r_result.is_a? RResultName)
|
149
205
|
inst_name = r_result.name
|
150
206
|
|
151
207
|
elem_to_match = @results.reverse.find{|elem| elem[0] == inst_name }
|
152
208
|
if elem_to_match.nil?
|
153
|
-
return
|
209
|
+
return RBridge::r_nil()
|
154
210
|
else
|
155
211
|
r_obj = elem_to_match[1]
|
156
212
|
if RBridge::is_r_nil?( r_obj )
|
157
|
-
return
|
213
|
+
return RBridge::r_nil()
|
158
214
|
else
|
159
215
|
return r_obj
|
160
216
|
end
|
@@ -170,7 +226,7 @@ module RBridge
|
|
170
226
|
}
|
171
227
|
|
172
228
|
if( index_array.all?(nil) )
|
173
|
-
return
|
229
|
+
return RBridge::r_nil()
|
174
230
|
else
|
175
231
|
index_array.delete(nil)
|
176
232
|
if ! index_array.empty?
|
@@ -178,13 +234,23 @@ module RBridge
|
|
178
234
|
r_obj = @results[last_idx][1]
|
179
235
|
return r_obj
|
180
236
|
else
|
181
|
-
return
|
237
|
+
return RBridge::r_nil()
|
182
238
|
end
|
183
239
|
end
|
184
240
|
else
|
185
241
|
raise "get_last_for() takes unexpected object"
|
186
242
|
end
|
187
243
|
end
|
244
|
+
|
245
|
+
def get_previous()
|
246
|
+
p @results
|
247
|
+
if @results.size > 0
|
248
|
+
r_obj = @results.last[1]
|
249
|
+
return r_obj
|
250
|
+
else
|
251
|
+
return RBridge::r_nil()
|
252
|
+
end
|
253
|
+
end
|
188
254
|
end
|
189
255
|
|
190
256
|
class RNameContainer
|
data/lib/r_bridge/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: r_bridge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Toshihiro Umehara
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -73,7 +73,7 @@ metadata:
|
|
73
73
|
homepage_uri: https://github.com/niceume/r_bridge
|
74
74
|
source_code_uri: https://github.com/niceume/r_bridge
|
75
75
|
changelog_uri: https://github.com/niceume/r_bridge
|
76
|
-
post_install_message:
|
76
|
+
post_install_message:
|
77
77
|
rdoc_options: []
|
78
78
|
require_paths:
|
79
79
|
- lib
|
@@ -89,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
89
|
version: '0'
|
90
90
|
requirements: []
|
91
91
|
rubygems_version: 3.1.2
|
92
|
-
signing_key:
|
92
|
+
signing_key:
|
93
93
|
specification_version: 4
|
94
94
|
summary: Enables Ruby to construct and evaluate R internal objects
|
95
95
|
test_files: []
|