rust 0.4 → 0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca9e5aaa6bcfff9d1b261c5a3ced5cf74b7731085b4b094dba55df72884aca9a
4
- data.tar.gz: 8c90363b44a0c95abc9610fb78c3c632c6ae4265ad2260ff7e9740777245f63e
3
+ metadata.gz: fe8f5c3e0753395fe3925f7a64eab0476308df329a9c9d594c74d1e568419204
4
+ data.tar.gz: 9f5371713565e77777deba19ba745bb358e0a23dfad6fb562e3940cf90cf8f1e
5
5
  SHA512:
6
- metadata.gz: 0ca17e2c0dda2188138f11e1ae4becaa8a5c4b0d2cc12273775b9ade1fefbc860f3ccee2251fbe353b9dbde55eded960e8cf26642af042070d979ed192b332e3
7
- data.tar.gz: 28dacd36f814acf51d222c8e746f65b94ef53ab5f24902ba6f654b05267c926e8db03cca82a876ca1183f55293da96d60ec862c5bfa26f6abd430d1f5e998709
6
+ metadata.gz: abf20b1c4cea07089c27ab886ff640886ff4e5f74d2b964b3ab959d413cdf1d34d72055e1d7141e3585df5adcdfbf5a53716d3cf7ca7b352ee02d4e39dda020b
7
+ data.tar.gz: c6c97cc64a50449bcf97a5d584f6a17b4e05762f79321ed9dcccfee496b567933f3fb0b4e8908c4f8029aeb0683cb7d86863586f7c200979f98911aa5b82c258
data/bin/ruby-rust ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/ruby
2
+
3
+ system "RUBY_RUST_BINDING=1 irb -r \"rust\""
@@ -1,15 +1,32 @@
1
- require_relative 'rust-core'
1
+ require_relative '../core'
2
+ require 'csv'
2
3
 
3
4
  module Rust
5
+
6
+ ##
7
+ # Class that handles CSVs (both loading and saving).
8
+
4
9
  class CSV
10
+
11
+ ##
12
+ # Reads a +pattern+ of CSVs (glob-style pattern) and returns a map containing as keys the filenames of the
13
+ # loaded CSVs and as values the corresponding data-frames. Options can be specified (see #read).
14
+
5
15
  def self.read_all(pattern, **options)
6
- result = {}
16
+ result = DataFrameHash.new
7
17
  Dir.glob(pattern).each do |filename|
8
18
  result[filename] = CSV.read(filename, **options)
9
19
  end
10
20
  return result
11
21
  end
12
22
 
23
+ ##
24
+ # Reads the CSV at +filename+. Options can be specified, such as:
25
+ # - headers => set to true if the first row contains the headers, false otherwise;
26
+ # - infer_numbers => if a column contains only numbers, the values are transformed into floats; true by default;
27
+ # - infer_integers => if infer_numbers is active, it distinguishes between integers and floats;
28
+ # The other options are the ones that can be used in the function R function "read.csv".
29
+
13
30
  def self.read(filename, **options)
14
31
  hash = {}
15
32
  labels = nil
@@ -45,14 +62,18 @@ module Rust
45
62
  return result
46
63
  end
47
64
 
65
+ ##
66
+ # Writes the +dataframe+ as a CSV at +filename+. Options can be specified, such as:
67
+ # - headers => set to true if the first row should contain the headers, false otherwise;
68
+ # The other options are the ones that can be used in the function R function "read.csv".
69
+
48
70
  def self.write(filename, dataframe, **options)
49
71
  raise TypeError, "Expected Rust::DataFrame" unless dataframe.is_a?(Rust::DataFrame)
50
72
 
51
73
  write_headers = options[:headers] != false
52
- options[:headers] = dataframe.column_names if options[:headers] == nil
74
+ options[:headers] = dataframe.column_names unless options[:headers]
53
75
 
54
76
  hash = {}
55
- labels = nil
56
77
  ::CSV.open(filename, 'w', write_headers: write_headers, **options) do |csv|
57
78
  dataframe.each do |row|
58
79
  csv << row
@@ -93,3 +114,13 @@ module Rust
93
114
  end
94
115
  end
95
116
  end
117
+
118
+ module Rust::RBindings
119
+ def read_csv(filename, **options)
120
+ Rust::CSV.read(filename, **options)
121
+ end
122
+
123
+ def write_csv(filename, dataframe, **options)
124
+ Rust::CSV.write(filename, dataframe, **options)
125
+ end
126
+ end
@@ -0,0 +1,221 @@
1
+ require 'code-assertions'
2
+ require 'stringio'
3
+ require 'rinruby'
4
+
5
+ ##
6
+ # Basic module for the Rust package. It includes a series of sub-modules that provide specific features, such as
7
+ # statistical hypothesis tests, plots, and so on.
8
+
9
+ module Rust
10
+ CLIENT_MUTEX = Mutex.new
11
+ R_MUTEX = Mutex.new
12
+
13
+ R_ENGINE = RinRuby.new(echo: false)
14
+
15
+ private_constant :R_ENGINE
16
+ private_constant :R_MUTEX
17
+ private_constant :CLIENT_MUTEX
18
+
19
+ @@debugging = $RUST_DEBUG || false
20
+ @@in_client_mutex = false
21
+
22
+ ##
23
+ # Sets the debug mode. Any call to R will be written on the standard output.
24
+
25
+ def self.debug
26
+ @@debugging = true
27
+ end
28
+
29
+ ##
30
+ # Checks if the debug mode is active.
31
+
32
+ def self.debug?
33
+ return @@debugging
34
+ end
35
+
36
+ ##
37
+ # Runs the given block with a mutex. It is mandatory to run any R command with this method.
38
+
39
+ def self.exclusive
40
+ result = nil
41
+ CLIENT_MUTEX.synchronize do
42
+ @@in_client_mutex = true
43
+ result = yield
44
+ @@in_client_mutex = false
45
+ end
46
+ return result
47
+ end
48
+
49
+ ##
50
+ # Sets a variable in the R environment with a given value.
51
+ #
52
+ # Raises an error if the value can not be translated into an R object.
53
+ #
54
+ # Example: Rust['a'] = 0.
55
+
56
+ def self.[]=(variable, value)
57
+ if value.is_a?(RustDatatype)
58
+ value.load_in_r_as(variable.to_s)
59
+ elsif value.is_a?(String) || value.is_a?(Numeric) || value.is_a?(Array) || value.is_a?(::Matrix)
60
+ R_ENGINE.assign(variable, value)
61
+ else
62
+ raise "Trying to assign #{variable} with #{value.class}; expected RustDatatype, String, Numeric, or Array"
63
+ end
64
+ end
65
+
66
+ ##
67
+ # Retrieves the value of a variable from the R environment.
68
+ #
69
+ # Example: Rust['a']
70
+
71
+ def self.[](variable)
72
+ return RustDatatype.pull_variable(variable)
73
+ end
74
+
75
+ def self._eval_big(r_command, return_warnings = false)
76
+ r_command = r_command.join("\n") if r_command.is_a?(Array)
77
+
78
+ self._rexec(r_command, return_warnings) do |cmd|
79
+ result = true
80
+ instructions = cmd.lines
81
+
82
+ while instructions.size > 0
83
+ current_command = ""
84
+
85
+ while (instructions.size > 0) && (current_command.length + instructions.first.length < 10000)
86
+ current_command << instructions.shift
87
+ end
88
+
89
+ result &= R_ENGINE.eval(current_command)
90
+ end
91
+
92
+ result
93
+ end
94
+ end
95
+
96
+ def self._pull(r_command, return_warnings = false)
97
+ self._rexec(r_command, return_warnings) { |cmd| R_ENGINE.pull(cmd) }
98
+ end
99
+
100
+ def self._eval(r_command, return_warnings = false)
101
+ self._rexec(r_command, return_warnings) { |cmd| R_ENGINE.eval(cmd) }
102
+ end
103
+
104
+ def self._rexec(r_command, return_warnings = false)
105
+ puts "Calling _rexec with command: #{r_command}" if @@debugging
106
+ R_MUTEX.synchronize do
107
+ assert("This command must be executed in an exclusive block") { @@in_client_mutex }
108
+
109
+ result = nil
110
+ begin
111
+ $stdout = StringIO.new
112
+ if return_warnings
113
+ R_ENGINE.echo(true, true)
114
+ else
115
+ R_ENGINE.echo(false, false)
116
+ end
117
+ result = yield(r_command)
118
+ ensure
119
+ R_ENGINE.echo(false, false)
120
+ warnings = $stdout.string
121
+ $stdout = STDOUT
122
+ end
123
+
124
+ if return_warnings
125
+ puts " Got #{warnings.size} warnings, with result #{result.inspect[0...100]}" if @@debugging
126
+ return result, warnings.lines.map { |w| w.strip.chomp }
127
+ else
128
+ puts " Result: #{result.inspect[0...100]}" if @@debugging
129
+ return result
130
+ end
131
+ end
132
+ end
133
+
134
+ ##
135
+ # Checks if the given +name+ library can be used. Returns true if it is available, false otherwise.
136
+
137
+ def self.check_library(name)
138
+ self.exclusive do
139
+ result, _ = self._pull("require(\"#{name}\", character.only = TRUE)", true)
140
+ return result
141
+ end
142
+ end
143
+
144
+ ##
145
+ # Loads the given +name+ library.
146
+
147
+ def self.load_library(name)
148
+ self.exclusive do
149
+ self._eval("library(\"#{name}\", character.only = TRUE)")
150
+ end
151
+
152
+ return nil
153
+ end
154
+
155
+ ##
156
+ # Installs the given +name+ library and its dependencies.
157
+
158
+ def self.install_library(name)
159
+ self.exclusive do
160
+ self._eval("install.packages(\"#{name}\", dependencies = TRUE)")
161
+ end
162
+
163
+ return nil
164
+ end
165
+
166
+ ##
167
+ # Installs the +library+ library if it is not available and loads it.
168
+
169
+ def self.prerequisite(library)
170
+ self.install_library(library) unless self.check_library(library)
171
+ self.load_library(library)
172
+ end
173
+
174
+ ##
175
+ # Ask for help on a given +mod+.
176
+
177
+ def self.help!(mod = nil)
178
+ unless mod
179
+ puts "You have the following modules:"
180
+ Rust.constants.map { |c| Rust.const_get(c) }.select { |c| c.class == Module }.each do |mod|
181
+ puts "\t- #{mod}"
182
+ end
183
+ puts "Run \"help! {module}\" for more detailed information about the module"
184
+ else
185
+ if mod.methods.include?(:help!)
186
+ mod.help!
187
+ else
188
+ puts "Sorry, no help available for #{mod}"
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ ##
195
+ # Module that contains methods that allow to call R functions faster. Such methods have names resembling the ones
196
+ # available in R (e.g., cor, wilcox_test).
197
+
198
+ module Rust::RBindings
199
+ def data_frame(*args)
200
+ Rust::DataFrame.new(*args)
201
+ end
202
+ end
203
+
204
+ module Rust::TestCases
205
+ def self.sample_dataframe(columns, size=100)
206
+ result = Rust::DataFrame.new(columns)
207
+ size.times do |i|
208
+ result << columns.map { |c| yield i, c }
209
+ end
210
+ return result
211
+ end
212
+ end
213
+
214
+ ##
215
+ # Shortcut for including the RBinding module
216
+
217
+ def bind_r!
218
+ include Rust::RBindings
219
+ end
220
+
221
+ bind_r! if ENV['RUBY_RUST_BINDING'] == '1'
@@ -0,0 +1,4 @@
1
+ self_path = File.expand_path(__FILE__)
2
+ Dir.glob(File.dirname(self_path) + "/*.rb").each do |lib|
3
+ require_relative lib unless lib == self_path
4
+ end