simpler 0.0.1
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/.document +5 -0
- data/.gitignore +24 -0
- data/History +4 -0
- data/LICENSE +20 -0
- data/README.rdoc +43 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/lib/simpler/data_frame.rb +45 -0
- data/lib/simpler/plot.rb +16 -0
- data/lib/simpler/reply.rb +22 -0
- data/lib/simpler.rb +99 -0
- data/spec/simpler_spec.rb +122 -0
- data/spec/spec_helper.rb +4 -0
- metadata +87 -0
data/.document
ADDED
data/.gitignore
ADDED
data/History
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 John Prince
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
= simpler
|
2
|
+
|
3
|
+
simpler ("simple R") is a lightweight wrapper that calls R (really Rscript)
|
4
|
+
from within ruby. It is designed to favor R in syntax.
|
5
|
+
|
6
|
+
=== Why use this rather than rsruby?
|
7
|
+
|
8
|
+
You should probably be using rsruby--it's a fantastic gem. However, if you
|
9
|
+
want to code using more of an R code sytax (e.g., to cut and paste R code and
|
10
|
+
have it just work), or if you can't get rsruby working, this gem may be useful
|
11
|
+
to you.
|
12
|
+
|
13
|
+
== Examples
|
14
|
+
|
15
|
+
require 'simpler'
|
16
|
+
|
17
|
+
Basic execution (Raw input in, raw input out)
|
18
|
+
|
19
|
+
sr = Simpler.new
|
20
|
+
sr.execute!("mean(c(1,2,3))") # -> "[1] 2\n" (a Simpler::Reply object)
|
21
|
+
|
22
|
+
Using ruby variables (calculating correlation coefficient):
|
23
|
+
|
24
|
+
xv = [1,2,7]
|
25
|
+
yv = [3,4,8]
|
26
|
+
reply = sr.go(xv,yv) do |x,y|
|
27
|
+
"cor(#{x},#{y})"
|
28
|
+
end
|
29
|
+
reply # -> "[1] 0.9994238\n"
|
30
|
+
|
31
|
+
For plotting on the fly (RScript)
|
32
|
+
|
33
|
+
== Credit
|
34
|
+
|
35
|
+
Simpler is loosely inspired by the original gnuplot and, of course, the excellent rsruby.
|
36
|
+
|
37
|
+
==Casting
|
38
|
+
|
39
|
+
All replies are of class Simpler::String, so casting can be done in a way that works for you by defining your own methods.
|
40
|
+
|
41
|
+
== Copyright
|
42
|
+
|
43
|
+
Copyright (c) 2010 John Prince. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'jeweler'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'rcov/rcovtask'
|
7
|
+
|
8
|
+
Jeweler::Tasks.new do |gem|
|
9
|
+
gem.name = "simpler"
|
10
|
+
gem.summary = %Q{simpler ("simple R")- A low-tech method to run R scripts. Allows you to basically copy and paste R code and run it.}
|
11
|
+
gem.description = %Q{you should check out rsruby first. This is a very low-tech way to run R. It does have the advantage of being able to run R code essentially unchanged.}
|
12
|
+
gem.email = "jtprince@gmail.com"
|
13
|
+
gem.homepage = "http://github.com/jtprince/simpler"
|
14
|
+
gem.authors = ["John Prince"]
|
15
|
+
gem.add_development_dependency "spec-more", ">= 0"
|
16
|
+
end
|
17
|
+
|
18
|
+
Rake::TestTask.new(:spec) do |spec|
|
19
|
+
spec.libs << 'lib' << 'spec'
|
20
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
21
|
+
spec.verbose = true
|
22
|
+
end
|
23
|
+
|
24
|
+
Rcov::RcovTask.new do |spec|
|
25
|
+
spec.libs << 'spec'
|
26
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
27
|
+
spec.verbose = true
|
28
|
+
end
|
29
|
+
|
30
|
+
task :default => :spec
|
31
|
+
|
32
|
+
Rake::RDocTask.new do |rdoc|
|
33
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
34
|
+
|
35
|
+
rdoc.rdoc_dir = 'rdoc'
|
36
|
+
rdoc.title = "simpler #{version}"
|
37
|
+
rdoc.rdoc_files.include('README*')
|
38
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
39
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
class Simpler
|
3
|
+
# This is an R-centric container for storing data
|
4
|
+
class DataFrame
|
5
|
+
# this is necessary for
|
6
|
+
attr_accessor :col_names
|
7
|
+
attr_accessor :row_names
|
8
|
+
attr_accessor :hash
|
9
|
+
# takes a hash, where the col_name is the key and the data rows are an
|
10
|
+
# array of values. The default ordering of the hash keys will be used,
|
11
|
+
# unless overridden with col_names. The row_names can be used to specify
|
12
|
+
# the names of the rows (remains nil if no values specified)
|
13
|
+
def initialize(hash, row_names=nil, col_names=nil)
|
14
|
+
@hash = hash
|
15
|
+
@row_names = row_names
|
16
|
+
@col_names = col_names || @hash.keys
|
17
|
+
end
|
18
|
+
|
19
|
+
# creates the code to transform the object into R code. If usefile is
|
20
|
+
# specified, the dataframe is written as a table and the code generated
|
21
|
+
# will read in the table as a data frame.
|
22
|
+
def to_r(usefile=nil)
|
23
|
+
if usefile
|
24
|
+
raise NotImplementedError, "not implemented just yet"
|
25
|
+
else
|
26
|
+
# build the vectors
|
27
|
+
lines = @col_names.map do |name|
|
28
|
+
val = @hash[name]
|
29
|
+
"#{Simpler.varname(val)} <- c(#{val.join(',')})"
|
30
|
+
end
|
31
|
+
args = @col_names.map do |name|
|
32
|
+
"#{name}=#{Simpler.varname(@hash[name])}"
|
33
|
+
end
|
34
|
+
if @row_names
|
35
|
+
varname = Simpler.varname(@row_names)
|
36
|
+
lines << "#{varname} <- c(#{@row_names.map {|v| "\"#{v}\""}.join(',')})"
|
37
|
+
args.push("row.names=#{varname}")
|
38
|
+
end
|
39
|
+
lines << "#{Simpler.varname(self)} <- data.frame(#{args.join(', ')})"
|
40
|
+
lines.join("\n") << "\n"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
data/lib/simpler/plot.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
class Simpler
|
3
|
+
module Plot
|
4
|
+
|
5
|
+
def plot(file_w_extension, opts={}, &block)
|
6
|
+
device = self.class.filename_to_plottype(file_w_extension)
|
7
|
+
opts_as_ropts = opts.map {|k,v| "#{k}=#{r_format(v)}"}
|
8
|
+
string = "#{device}(#{file_w_extension.inspect}, #{opts_as_ropts.join(', ')})\n"
|
9
|
+
string << block.call << "\n"
|
10
|
+
string << "dev.off()\n"
|
11
|
+
string
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
class Simpler
|
3
|
+
class Reply < String
|
4
|
+
|
5
|
+
# removes the [1] from the line
|
6
|
+
def rm_leader
|
7
|
+
gsub(/^\[\d+\] /,'')
|
8
|
+
end
|
9
|
+
|
10
|
+
def array_cast
|
11
|
+
self.chomp.split("\n").rm_leader.split(" ")
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_f
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_i
|
18
|
+
rm_leader.to_f
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/lib/simpler.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'simpler/data_frame'
|
3
|
+
require 'simpler/plot'
|
4
|
+
require 'simpler/reply'
|
5
|
+
|
6
|
+
class Array
|
7
|
+
def to_r(varname=nil)
|
8
|
+
varname ||= Simpler.varname(self)
|
9
|
+
"#{varname} <- c(#{self.join(',')})\n"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Simpler
|
14
|
+
include Plot
|
15
|
+
|
16
|
+
RPLOTS_FILE = "Rplots.pdf"
|
17
|
+
PDF_VIEWER = "evince"
|
18
|
+
|
19
|
+
# returns the variable name of the object
|
20
|
+
def self.varname(obj)
|
21
|
+
"rb#{obj.object_id}"
|
22
|
+
end
|
23
|
+
|
24
|
+
# returns it as a symbol, currently recognizes pdf, png, svg
|
25
|
+
def self.filename_to_plottype(name)
|
26
|
+
name.match(/\.([^\.]+)$/)[1].downcase.to_sym
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_accessor :commands
|
30
|
+
attr_accessor :pdf_viewer
|
31
|
+
|
32
|
+
def initialize(commands=[], opts={:pdf_viewer => PDF_VIEWER})
|
33
|
+
@pdf_viewer = opts[:pdf_viewer]
|
34
|
+
@commands = commands
|
35
|
+
end
|
36
|
+
|
37
|
+
def r_format(object)
|
38
|
+
case object
|
39
|
+
when String
|
40
|
+
object.inspect
|
41
|
+
when Numeric
|
42
|
+
object.to_s
|
43
|
+
else
|
44
|
+
object.to_s
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# displays the Rplots.pdf file at the end of execution
|
49
|
+
def show!(string=nil)
|
50
|
+
if File.exist?(RPLOTS_FILE)
|
51
|
+
original_mtime = File.mtime(RPLOTS_FILE)
|
52
|
+
end
|
53
|
+
reply = run!(string)
|
54
|
+
system "#{@pdf_viewer} #{RPLOTS_FILE} &"
|
55
|
+
reply
|
56
|
+
end
|
57
|
+
|
58
|
+
# pushes string onto command array (if given), executes all commands, and
|
59
|
+
# clears the command array.
|
60
|
+
def run!(string=nil)
|
61
|
+
@commands.push(string) if string
|
62
|
+
reply = nil
|
63
|
+
Open3.popen3("Rscript -") do |stdin, stdout, stderr|
|
64
|
+
stdin.puts @commands.map {|v| v + "\n"}.join
|
65
|
+
stdin.close_write
|
66
|
+
reply = stdout.read
|
67
|
+
end
|
68
|
+
@commands.clear
|
69
|
+
Simpler::Reply.new(reply)
|
70
|
+
end
|
71
|
+
|
72
|
+
# pushes string onto command array (if given), executes all commands, and
|
73
|
+
# clears the command array.
|
74
|
+
def run!(string=nil)
|
75
|
+
@commands.push(string) if string
|
76
|
+
reply = nil
|
77
|
+
Open3.popen3("Rscript -") do |stdin, stdout, stderr|
|
78
|
+
stdin.puts @commands.map {|v| v + "\n"}.join
|
79
|
+
stdin.close_write
|
80
|
+
reply = stdout.read
|
81
|
+
end
|
82
|
+
@commands.clear
|
83
|
+
Simpler::Reply.new(reply)
|
84
|
+
end
|
85
|
+
|
86
|
+
# returns self for chaining
|
87
|
+
def with(*objects, &block)
|
88
|
+
var_names = objects.map {|v| Simpler.varname(v) }
|
89
|
+
conversion_code = objects.map {|v| v.to_r }
|
90
|
+
@commands.push(*conversion_code)
|
91
|
+
@commands << block.call(*var_names)
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
def go(*objects, &block)
|
96
|
+
with(*objects, &block).run!
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'simpler'
|
4
|
+
|
5
|
+
describe "Simpler" do
|
6
|
+
before do
|
7
|
+
@typos = [2,3,0,3,1,0,0,1]
|
8
|
+
@rate = [2,4,0,3,1,3,0,0]
|
9
|
+
@r = Simpler.new
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can create valid commands" do
|
13
|
+
@r.with(@typos) {|t| "mean(#{t})" }
|
14
|
+
@r.commands.first.matches /rb\d+ <- c\(2,3,0,3,1,0,0,1\)/
|
15
|
+
@r.commands.last.matches /mean\(rb\d+\)/
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'can get a reply' do
|
19
|
+
reply = @r.run!("typos = c(2,3,0,3,1,0,0,1)\nmean(typos)\nhist(typos)")
|
20
|
+
reply.chomp.is "[1] 1.25"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'making data frames' do
|
26
|
+
before do
|
27
|
+
@hash = {
|
28
|
+
:one => [1,2,6,7],
|
29
|
+
:two => [3,4,2,9],
|
30
|
+
:three => [3,1,1,7],
|
31
|
+
}
|
32
|
+
@col_names = %w(one two three).map(&:to_sym)
|
33
|
+
@row_names = ['spicy', 'cool', 'wetness', 'relative humidity']
|
34
|
+
end
|
35
|
+
it 'makes data frames with row names' do
|
36
|
+
expected = %Q{ one two three
|
37
|
+
spicy 1 3 3
|
38
|
+
cool 2 4 1
|
39
|
+
wetness 6 2 1
|
40
|
+
relative humidity 7 9 7
|
41
|
+
}
|
42
|
+
df = Simpler::DataFrame.new(@hash, @row_names, @col_names)
|
43
|
+
as_data_frame = Simpler.new.with(df) {|df| df }.run!
|
44
|
+
as_data_frame.is expected
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'makes data frames with no row names' do
|
48
|
+
expected = %Q{ one two three
|
49
|
+
1 1 3 3
|
50
|
+
2 2 4 1
|
51
|
+
3 6 2 1
|
52
|
+
4 7 9 7
|
53
|
+
}
|
54
|
+
df = Simpler::DataFrame.new(@hash, nil, @col_names)
|
55
|
+
as_data_frame = Simpler.new.with(df) {|df| df }.run!
|
56
|
+
as_data_frame.is expected
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe 'making plots' do
|
61
|
+
|
62
|
+
before do
|
63
|
+
@x = [1,2,3,4,5,6]
|
64
|
+
@y = [3,5,4,7,8,2]
|
65
|
+
@file = "plot"
|
66
|
+
@exts = %w(svg pdf png).map(&:to_sym)
|
67
|
+
@r = Simpler.new
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'has convenience wrappers for plotting to file' do
|
71
|
+
@exts.each do |ext|
|
72
|
+
file = @file + "." + ext
|
73
|
+
@r.with(@x, @y) do |x,y|
|
74
|
+
@r.plot(file) do
|
75
|
+
%Q{
|
76
|
+
plot(#{x},#{y}, main="#{ext} scatterplot example", col=rgb(0,100,0,50,maxColorValue=255), pch=16)
|
77
|
+
}
|
78
|
+
end
|
79
|
+
end.run!
|
80
|
+
File.exist?(file).is true
|
81
|
+
IO.read(@file + ".svg").matches(/svg/) if ext == :svg
|
82
|
+
File.unlink(file)
|
83
|
+
end
|
84
|
+
# pdf and png matching giving: "ArgumentError: invalid byte sequence in UTF-8"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe 'showing plots' do
|
89
|
+
before do
|
90
|
+
module ::Kernel
|
91
|
+
alias_method :old_system, :system
|
92
|
+
def system(string) ; $SYSTEM_CALL = string end
|
93
|
+
end
|
94
|
+
@x = [1,2,3,4,5,6]
|
95
|
+
@y = [3,5,4,7,8,2]
|
96
|
+
@r = Simpler.new
|
97
|
+
end
|
98
|
+
|
99
|
+
after do
|
100
|
+
module ::Kernel
|
101
|
+
alias_method :system, :old_system
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'can disply plots' do
|
106
|
+
ok $SYSTEM_CALL.nil?
|
107
|
+
|
108
|
+
@r.with(@x, @y) do |x,y|
|
109
|
+
"plot(#{x}, #{y})"
|
110
|
+
end.show!
|
111
|
+
|
112
|
+
# this shows that we've made a system call to visualize the data
|
113
|
+
ok !$SYSTEM_CALL.nil?
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe 'ancillary functions' do
|
118
|
+
it 'can get the device from the filename' do
|
119
|
+
Simpler.filename_to_plottype("bob.the.pdf").is :pdf
|
120
|
+
Simpler.filename_to_plottype("larry.the.svg").is :svg
|
121
|
+
end
|
122
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simpler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- John Prince
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-07-09 00:00:00 -06:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: spec-more
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :development
|
31
|
+
version_requirements: *id001
|
32
|
+
description: you should check out rsruby first. This is a very low-tech way to run R. It does have the advantage of being able to run R code essentially unchanged.
|
33
|
+
email: jtprince@gmail.com
|
34
|
+
executables: []
|
35
|
+
|
36
|
+
extensions: []
|
37
|
+
|
38
|
+
extra_rdoc_files:
|
39
|
+
- LICENSE
|
40
|
+
- README.rdoc
|
41
|
+
files:
|
42
|
+
- .document
|
43
|
+
- .gitignore
|
44
|
+
- History
|
45
|
+
- LICENSE
|
46
|
+
- README.rdoc
|
47
|
+
- Rakefile
|
48
|
+
- VERSION
|
49
|
+
- lib/simpler.rb
|
50
|
+
- lib/simpler/data_frame.rb
|
51
|
+
- lib/simpler/plot.rb
|
52
|
+
- lib/simpler/reply.rb
|
53
|
+
- spec/simpler_spec.rb
|
54
|
+
- spec/spec_helper.rb
|
55
|
+
has_rdoc: true
|
56
|
+
homepage: http://github.com/jtprince/simpler
|
57
|
+
licenses: []
|
58
|
+
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options:
|
61
|
+
- --charset=UTF-8
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
requirements: []
|
79
|
+
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 1.3.6
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: simpler ("simple R")- A low-tech method to run R scripts. Allows you to basically copy and paste R code and run it.
|
85
|
+
test_files:
|
86
|
+
- spec/simpler_spec.rb
|
87
|
+
- spec/spec_helper.rb
|