r_bridge 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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: []
|