jdbc-wrapper 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README +13 -0
- data/Rakefile +25 -0
- data/examples/derby.rb +21 -0
- data/examples/h2.rb +15 -0
- data/examples/mysql.rb +15 -0
- data/lib/jdbc/adapters/derby.rb +29 -0
- data/lib/jdbc/adapters/h2.rb +23 -0
- data/lib/jdbc/adapters/hsqldb.rb +23 -0
- data/lib/jdbc/adapters/mysql.rb +24 -0
- data/lib/jdbc/adapters/postgresql.rb +24 -0
- data/lib/jdbc/adapters.rb +7 -0
- data/lib/jdbc/db.rb +85 -0
- data/lib/jdbc/prepared_statement.rb +31 -0
- data/lib/jdbc/result.rb +106 -0
- data/lib/jdbc.rb +11 -0
- data/test/test_db.rb +38 -0
- data/test/test_prepared_statement.rb +46 -0
- metadata +63 -0
data/README
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Minimum Requirements
|
2
|
+
====================
|
3
|
+
|
4
|
+
* Java 1.5
|
5
|
+
* JRuby 1.1 (tested with RC2)
|
6
|
+
* JDBC Drivers
|
7
|
+
|
8
|
+
How to Install
|
9
|
+
==============
|
10
|
+
|
11
|
+
* gem install jdbc-wrapper
|
12
|
+
* get your jdbc driver jars on your classpath
|
13
|
+
(the easier way to do this is drop them in $JRUBY_HOME/lib)
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
desc 'run all unit tests'
|
2
|
+
task :test do
|
3
|
+
require 'rake/runtest'
|
4
|
+
Rake.run_tests 'test/test_*.rb'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
Gem::manage_gems
|
9
|
+
require 'rake/gempackagetask'
|
10
|
+
|
11
|
+
gemspec = Gem::Specification.new do |s|
|
12
|
+
s.name = "jdbc-wrapper"
|
13
|
+
s.version = "0.2"
|
14
|
+
s.author = "Larry Myers"
|
15
|
+
s.email = "larry@larrymyers.com"
|
16
|
+
s.platform = Gem::Platform::RUBY
|
17
|
+
s.summary = "A basic JDBC wrapper for JRuby"
|
18
|
+
s.files = FileList["{examples,lib,test}/**/*","Rakefile","README"].to_a
|
19
|
+
s.require_path = "lib"
|
20
|
+
s.has_rdoc = false
|
21
|
+
end
|
22
|
+
|
23
|
+
Rake::GemPackageTask.new(gemspec) do |pkg|
|
24
|
+
pkg.need_tar = true
|
25
|
+
end
|
data/examples/derby.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'jdbc'
|
5
|
+
|
6
|
+
db_path = File.join(File.dirname(__FILE__),'..','derby-example')
|
7
|
+
|
8
|
+
JDBC::DB.start(:derby,nil,nil,nil,nil,db_path) do |db|
|
9
|
+
db.query("CREATE TABLE records " +
|
10
|
+
"(name VARCHAR(80), created_on TIMESTAMP)")
|
11
|
+
|
12
|
+
db.query("INSERT INTO records (name, created_on) " +
|
13
|
+
"VALUES ('foo', '#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}')")
|
14
|
+
|
15
|
+
db.query("SELECT * FROM records").each_hash do |row|
|
16
|
+
puts row
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
FileUtils.rm_r(db_path, :force => true) if File.exist?(db_path)
|
21
|
+
FileUtils.rm("derby.log") if File.exist?("derby.log")
|
data/examples/h2.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
2
|
+
|
3
|
+
require 'jdbc'
|
4
|
+
|
5
|
+
JDBC::DB.start(:h2,nil,nil,nil,nil,'foo') do |db|
|
6
|
+
db.query("CREATE TABLE records " +
|
7
|
+
"(name VARCHAR(80), created_on TIMESTAMP)")
|
8
|
+
|
9
|
+
db.query("INSERT INTO records (name, created_on) " +
|
10
|
+
"VALUES ('foo', '#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}')")
|
11
|
+
|
12
|
+
db.query("SELECT * FROM records").each_hash do |row|
|
13
|
+
row.each { |k,v| puts "#{k} = #{v}" }
|
14
|
+
end
|
15
|
+
end
|
data/examples/mysql.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
2
|
+
|
3
|
+
require 'jdbc'
|
4
|
+
|
5
|
+
JDBC::DB.start(:mysql,"localhost","3306","root","root","tasks_dev") do |db|
|
6
|
+
db.query("select * from jobs limit 1").each do |row|
|
7
|
+
row.each { |v| puts v }
|
8
|
+
puts
|
9
|
+
end
|
10
|
+
|
11
|
+
db.query("select * from jobs limit 1").each_hash do |row|
|
12
|
+
row.each { |k,v| puts "#{k} = #{v}, #{v.class}" }
|
13
|
+
puts
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module JDBC
|
2
|
+
module Adapters
|
3
|
+
class Derby
|
4
|
+
attr_reader :host, :port, :user, :password, :schema
|
5
|
+
|
6
|
+
def initialize(host, port, user, password, schema)
|
7
|
+
@host = host
|
8
|
+
@port = port
|
9
|
+
@user = user
|
10
|
+
@password = password
|
11
|
+
@schema = schema
|
12
|
+
end
|
13
|
+
|
14
|
+
def connection_string
|
15
|
+
str = "jdbc:derby:#{@schema}"
|
16
|
+
|
17
|
+
if ! File.exist?(@schema)
|
18
|
+
str << ";create=true"
|
19
|
+
end
|
20
|
+
|
21
|
+
return str
|
22
|
+
end
|
23
|
+
|
24
|
+
def class_name
|
25
|
+
"org.apache.derby.jdbc.EmbeddedDriver"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module JDBC
|
2
|
+
module Adapters
|
3
|
+
class H2
|
4
|
+
attr_reader :host, :port, :user, :password, :schema
|
5
|
+
|
6
|
+
def initialize(host, port, user, password, schema)
|
7
|
+
@host = host
|
8
|
+
@port = port
|
9
|
+
@user = user
|
10
|
+
@password = password
|
11
|
+
@schema = schema
|
12
|
+
end
|
13
|
+
|
14
|
+
def connection_string
|
15
|
+
"jdbc:h2:mem:#{@schema}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def class_name
|
19
|
+
"org.h2.Driver"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module JDBC
|
2
|
+
module Adapters
|
3
|
+
class Hsqldb
|
4
|
+
attr_reader :host, :port, :user, :password, :schema
|
5
|
+
|
6
|
+
def initialize(host, port, user, password, schema)
|
7
|
+
@host = host
|
8
|
+
@port = port
|
9
|
+
@user = user
|
10
|
+
@password = password
|
11
|
+
@schema = schema
|
12
|
+
end
|
13
|
+
|
14
|
+
def connection_string
|
15
|
+
"jdbc:hsqldb:mem:#{@schema}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def class_name
|
19
|
+
"org.hsqldb.jdbcDriver"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module JDBC
|
2
|
+
module Adapters
|
3
|
+
class Mysql
|
4
|
+
attr_reader :host, :port, :user, :password, :schema
|
5
|
+
|
6
|
+
def initialize(host, port, user, password, schema)
|
7
|
+
@host = host
|
8
|
+
@port = port
|
9
|
+
@user = user
|
10
|
+
@password = password
|
11
|
+
@schema = schema
|
12
|
+
end
|
13
|
+
|
14
|
+
def connection_string
|
15
|
+
"jdbc:mysql://#{@host}:#{@port}/#{@schema}" +
|
16
|
+
"?user=#{@user}&password=#{@password}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def class_name
|
20
|
+
"com.mysql.jdbc.Driver"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module JDBC
|
2
|
+
module Adapters
|
3
|
+
class Postgresql
|
4
|
+
attr_reader :host, :port, :user, :password, :schema
|
5
|
+
|
6
|
+
def initialize(host, port, user, password, schema)
|
7
|
+
@host = host
|
8
|
+
@port = port
|
9
|
+
@user = user
|
10
|
+
@password = password
|
11
|
+
@schema = schema
|
12
|
+
end
|
13
|
+
|
14
|
+
def connection_string
|
15
|
+
"jdbc:postgresql://#{@host}:#{@port}/#{@schema}" +
|
16
|
+
"?user=#{@user}&password=#{@password}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def class_name
|
20
|
+
"org.postgresql.Driver"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/jdbc/db.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'.')
|
2
|
+
|
3
|
+
require 'java'
|
4
|
+
require 'time'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
require 'adapters'
|
8
|
+
|
9
|
+
module JDBC
|
10
|
+
class DB
|
11
|
+
def initialize(engine, host, port, user, password, schema)
|
12
|
+
adapter = get_adapter(engine, host, port, user, password, schema)
|
13
|
+
|
14
|
+
begin
|
15
|
+
java.lang.Class.forName(adapter.class_name).newInstance()
|
16
|
+
|
17
|
+
@conn = JavaSql::DriverManager.getConnection(
|
18
|
+
adapter.connection_string)
|
19
|
+
rescue JavaSql::SQLException => e
|
20
|
+
raise RuntimeError.new(e.message)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.start(db_class, host, port, user, password, database)
|
25
|
+
db = nil
|
26
|
+
|
27
|
+
begin
|
28
|
+
db = DB.new(db_class, host, port, user, password, database)
|
29
|
+
|
30
|
+
yield(db)
|
31
|
+
rescue JavaSql::SQLException => e
|
32
|
+
raise RuntimeError.new(e.message)
|
33
|
+
ensure
|
34
|
+
db.close unless db.nil?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def query(sql)
|
39
|
+
stmt = nil
|
40
|
+
result = nil
|
41
|
+
|
42
|
+
begin
|
43
|
+
stmt = @conn.createStatement
|
44
|
+
|
45
|
+
res = stmt.execute(sql)
|
46
|
+
|
47
|
+
if res == false
|
48
|
+
return stmt.getUpdateCount
|
49
|
+
end
|
50
|
+
|
51
|
+
return Result.new(stmt.getResultSet, stmt)
|
52
|
+
rescue JavaSql::SQLException => e
|
53
|
+
stmt.close unless stmt.nil?
|
54
|
+
raise RuntimeError.new(e.message)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def prepare(sql)
|
59
|
+
return PreparedStatement.new(@conn.prepareStatement(sql))
|
60
|
+
end
|
61
|
+
|
62
|
+
def close
|
63
|
+
@conn.close unless @conn.nil?
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def get_adapter(engine, host, port, user, password, schema)
|
69
|
+
case engine
|
70
|
+
when :derby
|
71
|
+
return Adapters::Derby.new(host, port, user, password, schema)
|
72
|
+
when :h2
|
73
|
+
return Adapters::H2.new(host, port, user, password, schema)
|
74
|
+
when :hsqldb
|
75
|
+
return Adapters::Hsqldb.new(host, port, user, password, schema)
|
76
|
+
when :mysql
|
77
|
+
return Adapters::Mysql.new(host, port, user, password, schema)
|
78
|
+
when :postgresql
|
79
|
+
return Adapters::Postgresql.new(host, port, user, password, schema)
|
80
|
+
end
|
81
|
+
|
82
|
+
raise InvalidException("#{engine} is not supported.")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module JDBC
|
2
|
+
class PreparedStatement
|
3
|
+
def initialize(stmt)
|
4
|
+
@stmt = stmt
|
5
|
+
@meta_data = stmt.getParameterMetaData
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute(*args)
|
9
|
+
if args.length != @meta_data.getParameterCount
|
10
|
+
raise RuntimeError.new("Got #{args.length} params, " +
|
11
|
+
"expected #{@meta_data.getParameterCount}.")
|
12
|
+
end
|
13
|
+
|
14
|
+
@stmt.clearParameters
|
15
|
+
|
16
|
+
args.each_with_index do |arg, i|
|
17
|
+
@stmt.setObject(i+1, arg, @meta_data.getParameterType(i+1))
|
18
|
+
end
|
19
|
+
|
20
|
+
if @stmt.execute
|
21
|
+
return Result.new(@stmt.getResultSet, @stmt)
|
22
|
+
end
|
23
|
+
|
24
|
+
return @stmt.getUpdateCount
|
25
|
+
end
|
26
|
+
|
27
|
+
def close
|
28
|
+
@stmt.close
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/jdbc/result.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
module JDBC
|
2
|
+
class Result
|
3
|
+
def initialize(resultSet, statement)
|
4
|
+
@rs = resultSet
|
5
|
+
@stmt = statement
|
6
|
+
@columns = get_rs_meta_data
|
7
|
+
end
|
8
|
+
|
9
|
+
def fetch
|
10
|
+
if @rs.next
|
11
|
+
result = []
|
12
|
+
|
13
|
+
@columns.each do |column|
|
14
|
+
result << fetch_and_cast(@rs, column)
|
15
|
+
end
|
16
|
+
|
17
|
+
return result
|
18
|
+
end
|
19
|
+
|
20
|
+
close
|
21
|
+
|
22
|
+
return nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def fetch_hash
|
26
|
+
if @rs.next
|
27
|
+
result = {}
|
28
|
+
|
29
|
+
@columns.each do |column|
|
30
|
+
result[column[:name]] = fetch_and_cast(@rs, column)
|
31
|
+
end
|
32
|
+
|
33
|
+
return result
|
34
|
+
end
|
35
|
+
|
36
|
+
close
|
37
|
+
|
38
|
+
return nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def each
|
42
|
+
while(result = fetch)
|
43
|
+
yield(result)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def each_hash
|
48
|
+
while(result = fetch_hash)
|
49
|
+
yield(result)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def close
|
54
|
+
@rs.close unless @rs.nil?
|
55
|
+
@stmt.close unless @stmt.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def get_rs_meta_data
|
61
|
+
meta_data = @rs.getMetaData
|
62
|
+
|
63
|
+
columns = []
|
64
|
+
|
65
|
+
meta_data.getColumnCount.times do |i|
|
66
|
+
columns << {
|
67
|
+
:name => meta_data.getColumnName(i+1).downcase,
|
68
|
+
:type => meta_data.getColumnType(i+1)
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
return columns
|
73
|
+
end
|
74
|
+
|
75
|
+
def fetch_and_cast(rs, column)
|
76
|
+
if column[:type] == JavaSql::Types::NULL
|
77
|
+
return nil
|
78
|
+
end
|
79
|
+
|
80
|
+
if column[:type] == JavaSql::Types::INTEGER ||
|
81
|
+
column[:type] == JavaSql::Types::SMALLINT ||
|
82
|
+
column[:type] == JavaSql::Types::TINYINT ||
|
83
|
+
column[:type] == JavaSql::Types::BIGINT
|
84
|
+
return rs.getInt(column[:name])
|
85
|
+
end
|
86
|
+
|
87
|
+
if column[:type] == JavaSql::Types::DECIMAL ||
|
88
|
+
column[:type] == JavaSql::Types::FLOAT
|
89
|
+
return rs.getDouble(column[:name])
|
90
|
+
end
|
91
|
+
|
92
|
+
if column[:type] == JavaSql::Types::DATE ||
|
93
|
+
column[:type] == JavaSql::Types::TIME ||
|
94
|
+
column[:type] == JavaSql::Types::TIMESTAMP
|
95
|
+
|
96
|
+
val = rs.getString(column[:name])
|
97
|
+
|
98
|
+
return nil if val.nil?
|
99
|
+
|
100
|
+
return Time.parse(val)
|
101
|
+
end
|
102
|
+
|
103
|
+
return rs.getString(column[:name])
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/jdbc.rb
ADDED
data/test/test_db.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'jdbc'
|
5
|
+
|
6
|
+
class TestDB < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@db = JDBC::DB.new(:h2,nil,nil,nil,nil,'test')
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@db.close
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_create_table
|
16
|
+
assert_equal(0, create_records_table)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_insert_and_select
|
20
|
+
create_records_table
|
21
|
+
|
22
|
+
count = @db.query("INSERT INTO records (name) VALUES ('foo')")
|
23
|
+
|
24
|
+
assert_equal(1, count)
|
25
|
+
|
26
|
+
result = @db.query("SELECT * FROM records").fetch
|
27
|
+
|
28
|
+
assert_equal('foo', result[0])
|
29
|
+
|
30
|
+
result = @db.query("SELECT * FROM records").fetch_hash
|
31
|
+
|
32
|
+
assert_equal('foo', result['name'])
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_records_table
|
36
|
+
@db.query("CREATE TABLE records (name VARCHAR(80))")
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'jdbc'
|
5
|
+
|
6
|
+
class TestDB < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@db = JDBC::DB.new(:h2,nil,nil,nil,nil,'test')
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@db.close
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_insert_and_select
|
16
|
+
create_and_populate_records_table
|
17
|
+
|
18
|
+
stmt = @db.prepare("INSERT INTO records (name,id) VALUES (?,?)")
|
19
|
+
|
20
|
+
assert_equal(1, stmt.execute('bar', 2))
|
21
|
+
|
22
|
+
stmt = @db.prepare("SELECT * FROM records where id = ?")
|
23
|
+
|
24
|
+
row = stmt.execute(2).fetch
|
25
|
+
|
26
|
+
assert_equal('bar', row[0])
|
27
|
+
assert_equal(2, row[1])
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_runtime_error_on_invalid_arg_count
|
31
|
+
create_and_populate_records_table
|
32
|
+
|
33
|
+
stmt = @db.prepare("SELECT * FROM records WHERE name = ?")
|
34
|
+
|
35
|
+
begin
|
36
|
+
stmt.execute('arg1','bad_arg2')
|
37
|
+
flunk
|
38
|
+
rescue RuntimeError => e
|
39
|
+
assert_equal("Got 2 params, expected 1.", e.message)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_and_populate_records_table
|
44
|
+
@db.query("CREATE TABLE records (name VARCHAR(80), id INT)")
|
45
|
+
end
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
extensions: []
|
3
|
+
homepage:
|
4
|
+
executables: []
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: !str 0.2
|
7
|
+
post_install_message:
|
8
|
+
date: 2008-03-13 04:00:00 +00:00
|
9
|
+
files:
|
10
|
+
- examples/derby.rb
|
11
|
+
- examples/h2.rb
|
12
|
+
- examples/mysql.rb
|
13
|
+
- lib/jdbc
|
14
|
+
- lib/jdbc.rb
|
15
|
+
- lib/jdbc/adapters
|
16
|
+
- lib/jdbc/adapters.rb
|
17
|
+
- lib/jdbc/db.rb
|
18
|
+
- lib/jdbc/prepared_statement.rb
|
19
|
+
- lib/jdbc/result.rb
|
20
|
+
- lib/jdbc/adapters/derby.rb
|
21
|
+
- lib/jdbc/adapters/h2.rb
|
22
|
+
- lib/jdbc/adapters/hsqldb.rb
|
23
|
+
- lib/jdbc/adapters/mysql.rb
|
24
|
+
- lib/jdbc/adapters/postgresql.rb
|
25
|
+
- test/test_db.rb
|
26
|
+
- test/test_prepared_statement.rb
|
27
|
+
- Rakefile
|
28
|
+
- README
|
29
|
+
rubygems_version: 1.0.1
|
30
|
+
rdoc_options: []
|
31
|
+
signing_key:
|
32
|
+
cert_chain: []
|
33
|
+
name: jdbc-wrapper
|
34
|
+
has_rdoc: false
|
35
|
+
platform: ruby
|
36
|
+
summary: A basic JDBC wrapper for JRuby
|
37
|
+
default_executable:
|
38
|
+
bindir: bin
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
version:
|
41
|
+
requirements:
|
42
|
+
- - '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: !str 0
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
version:
|
47
|
+
requirements:
|
48
|
+
- - '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: !str 0
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
specification_version: 2
|
54
|
+
test_files: []
|
55
|
+
dependencies: []
|
56
|
+
description:
|
57
|
+
email: larry@larrymyers.com
|
58
|
+
authors:
|
59
|
+
- Larry Myers
|
60
|
+
extra_rdoc_files: []
|
61
|
+
requirements: []
|
62
|
+
rubyforge_project:
|
63
|
+
autorequire:
|