rubyhaze 0.0.1-jruby
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/LICENSE +20 -0
- data/README.rdoc +67 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/bin/rh_console +7 -0
- data/lib/rubyhaze/base_mixin.rb +40 -0
- data/lib/rubyhaze/client.rb +12 -0
- data/lib/rubyhaze/core_ext.rb +76 -0
- data/lib/rubyhaze/list.rb +12 -0
- data/lib/rubyhaze/lock.rb +12 -0
- data/lib/rubyhaze/map.rb +96 -0
- data/lib/rubyhaze/multi_map.rb +12 -0
- data/lib/rubyhaze/node.rb +12 -0
- data/lib/rubyhaze/queue.rb +12 -0
- data/lib/rubyhaze/set.rb +12 -0
- data/lib/rubyhaze/stored.rb +184 -0
- data/lib/rubyhaze/stores/fake_store.rb +25 -0
- data/lib/rubyhaze/topic.rb +21 -0
- data/lib/rubyhaze.rb +52 -0
- data/test/test_stored.rb +85 -0
- metadata +93 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Adrian Madrid
|
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,67 @@
|
|
1
|
+
= rubyhaze-0.0.1
|
2
|
+
|
3
|
+
JRuby convenience library to connect with {Hazelcast}[http://hazelcast.com]. According to the website:
|
4
|
+
|
5
|
+
Hazelcast is an open source clustering and highly scalable data distribution platform for Java, which is:
|
6
|
+
|
7
|
+
* Lightning-fast; thousands of operations/sec.
|
8
|
+
* Fail-safe; no losing data after crashes.
|
9
|
+
* Dynamically scales as new servers added.
|
10
|
+
* Super-easy to use; include a single jar.
|
11
|
+
|
12
|
+
== Getting started
|
13
|
+
|
14
|
+
Let's get the gem installed and test out the interactive console.
|
15
|
+
|
16
|
+
rvm jruby
|
17
|
+
gem install rubyhaze
|
18
|
+
export HAZELCAST_JAR_PATH=/my/own/path/hazelcast-1.8.5.jar
|
19
|
+
rh_console
|
20
|
+
|
21
|
+
hash = RH::Hash[:test]
|
22
|
+
hash[:a] = 1
|
23
|
+
hash[:b] = 2
|
24
|
+
|
25
|
+
Let's open another console to check how this distributed hash works:
|
26
|
+
|
27
|
+
rh_console
|
28
|
+
|
29
|
+
hash = RH::Hash[:test]
|
30
|
+
hash[:a]
|
31
|
+
|
32
|
+
>> 1
|
33
|
+
|
34
|
+
== Distributed Objects
|
35
|
+
|
36
|
+
Now let's share our own objects:
|
37
|
+
|
38
|
+
rh_console
|
39
|
+
|
40
|
+
class Foo
|
41
|
+
include RubyHaze::Stored
|
42
|
+
field :name, :string
|
43
|
+
field :age, :int
|
44
|
+
end
|
45
|
+
|
46
|
+
a = Foo.create :name => "Leonardo", :age => 65
|
47
|
+
b = Foo.create :name => "Michelangelo", :age => 45
|
48
|
+
c = Foo.create :name => "Raffaello", :age => 32
|
49
|
+
|
50
|
+
found = Foo.find 'age BETWEEN 40 AND 50'
|
51
|
+
found.first.name
|
52
|
+
|
53
|
+
>> "Michelangelo"
|
54
|
+
|
55
|
+
== Note on Patches/Pull Requests
|
56
|
+
|
57
|
+
* Fork the project.
|
58
|
+
* Make your feature addition or bug fix.
|
59
|
+
* Add tests for it. This is important so I don't break it in a
|
60
|
+
future version unintentionally.
|
61
|
+
* Commit, do not mess with rakefile, version, or history.
|
62
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
63
|
+
* Send me a pull request. Bonus points for topic branches.
|
64
|
+
|
65
|
+
== Copyright
|
66
|
+
|
67
|
+
Copyright (c) 2010 Adrian Madrid. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |gem|
|
9
|
+
gem.name = "rubyhaze"
|
10
|
+
gem.summary = %Q{JRuby convenience library to connect with Hazelcast}
|
11
|
+
gem.description = %Q{JRuby convenience library to connect with Hazelcast}
|
12
|
+
gem.email = "aemadrid@gmail.com"
|
13
|
+
gem.homepage = "http://github.com/aemadrid/rubyhaze"
|
14
|
+
gem.authors = ["Adrian Madrid"]
|
15
|
+
gem.files = FileList['bin/*', 'lib/**/*.rb', 'test/**/*.rb', '[A-Z]*'].to_a
|
16
|
+
gem.test_files = Dir["test/test*.rb"]
|
17
|
+
gem.platform = "jruby"
|
18
|
+
gem.add_dependency "bitescript"
|
19
|
+
end
|
20
|
+
Jeweler::GemcutterTasks.new
|
21
|
+
rescue LoadError
|
22
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
23
|
+
end
|
24
|
+
|
25
|
+
Rake::TestTask.new :test do |t|
|
26
|
+
t.libs << "lib"
|
27
|
+
t.test_files = FileList["test/**/test*.rb"]
|
28
|
+
end
|
29
|
+
|
30
|
+
task :test => :check_dependencies
|
31
|
+
|
32
|
+
task :default => :test
|
33
|
+
|
34
|
+
begin
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |spec|
|
37
|
+
spec.libs << 'spec'
|
38
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
39
|
+
spec.verbose = true
|
40
|
+
end
|
41
|
+
rescue LoadError
|
42
|
+
task :rcov do
|
43
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
require 'rake/rdoctask'
|
48
|
+
Rake::RDocTask.new do |rdoc|
|
49
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
50
|
+
|
51
|
+
rdoc.rdoc_dir = 'rdoc'
|
52
|
+
rdoc.title = "rubyhaze #{version}"
|
53
|
+
rdoc.rdoc_files.include('README*')
|
54
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/bin/rh_console
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module RubyHaze::BaseMixin
|
2
|
+
|
3
|
+
java_import 'com.hazelcast.core.Hazelcast'
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
def crc
|
12
|
+
@crc ||= RubyHaze.crc @name
|
13
|
+
end
|
14
|
+
|
15
|
+
def respond_to?(meth)
|
16
|
+
@hco.respond_to?(meth) || super
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(meth, *args, &blk)
|
20
|
+
if @hco.respond_to? meth
|
21
|
+
@hco.send meth, *args, &blk
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def ==(other)
|
28
|
+
return false unless other.class.name == self.class.name
|
29
|
+
name == other.name
|
30
|
+
end
|
31
|
+
|
32
|
+
module ClassMethods
|
33
|
+
|
34
|
+
def [](name)
|
35
|
+
new(name)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'java'
|
2
|
+
|
3
|
+
module RubyHaze
|
4
|
+
|
5
|
+
MODE = "client" unless defined? MODE
|
6
|
+
GEM_JAR_PATH = File.expand_path(File.dirname(__FILE__) + '/../../jars/hazelcast-client-1.8.5.jar') unless defined? GEM_JAR_PATH
|
7
|
+
JAR_PATH = ENV['HAZELCAST_JAR_PATH'] || GEM_JAR_PATH unless defined? JAR_PATH
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../lib/rubyhaze')
|
12
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Taken from http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/100177
|
2
|
+
class Exception
|
3
|
+
def errmsg
|
4
|
+
"%s: %s\n%s" % [self.class, message, (backtrace || []).join("\n") << "\n"]
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
# Taken from Active Support
|
9
|
+
class Array
|
10
|
+
# Extracts options from a set of arguments. Removes and returns the last
|
11
|
+
# element in the array if it's a hash, otherwise returns a blank hash.
|
12
|
+
#
|
13
|
+
# def options(*args)
|
14
|
+
# args.extract_options!
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# options(1, 2) # => {}
|
18
|
+
# options(1, 2, :a => :b) # => {:a=>:b}
|
19
|
+
def extract_options!
|
20
|
+
last.is_a?(::Hash) ? pop : {}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Extracted from truthy (http://github.com/ymendel/truthy/tree/master/lib/truthy.rb)
|
25
|
+
# and Rails (http://github.com/rails/rails/commit/823b623fe2de8846c37aa13250010809ac940b57) although changed to NOT look for private methods
|
26
|
+
|
27
|
+
class Object
|
28
|
+
|
29
|
+
# Tricky, tricky! (-:
|
30
|
+
def truthy?
|
31
|
+
!!self
|
32
|
+
end
|
33
|
+
|
34
|
+
# Tries to send the method only if object responds to it. Return +nil+ otherwise.
|
35
|
+
# It will also forward any arguments and/or block like Object#send does.
|
36
|
+
#
|
37
|
+
# ==== Example :
|
38
|
+
#
|
39
|
+
# # Without try
|
40
|
+
# @person ? @person.name : nil
|
41
|
+
#
|
42
|
+
# With try
|
43
|
+
# @person.try(:name)
|
44
|
+
#
|
45
|
+
# # try also accepts arguments/blocks for the method it is trying
|
46
|
+
# Person.try(:find, 1)
|
47
|
+
# @people.try(:map) {|p| p.name}
|
48
|
+
#
|
49
|
+
def try(method, *args, &block)
|
50
|
+
send(method, *args, &block) if respond_to?(method, true)
|
51
|
+
end
|
52
|
+
|
53
|
+
# List unique local methods
|
54
|
+
# Taken from http://giantrobots.thoughtbot.com/2008/12/23/script-console-tips
|
55
|
+
def local_methods
|
56
|
+
(methods - Object.instance_methods).sort
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
class String
|
62
|
+
def lines
|
63
|
+
self.split("\n").size
|
64
|
+
end
|
65
|
+
|
66
|
+
def valid_uuid_str(uuid)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.random_uuid
|
70
|
+
java.util.UUID.randomUUID.toString
|
71
|
+
end
|
72
|
+
|
73
|
+
def valid_uuid?
|
74
|
+
!!(size == 36 && self =~ %r{^([A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12})$}i)
|
75
|
+
end
|
76
|
+
end
|
data/lib/rubyhaze/map.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../lib/rubyhaze')
|
2
|
+
|
3
|
+
class RubyHaze::Map
|
4
|
+
|
5
|
+
include RubyHaze::BaseMixin
|
6
|
+
|
7
|
+
java_import 'com.hazelcast.query.SqlPredicate'
|
8
|
+
|
9
|
+
def initialize(name)
|
10
|
+
@name = name.to_s
|
11
|
+
@hco = Hazelcast.get_map @name
|
12
|
+
rescue => e
|
13
|
+
puts e.errmsg
|
14
|
+
end
|
15
|
+
|
16
|
+
def each
|
17
|
+
@hco.each do |(key, value)|
|
18
|
+
yield key, value
|
19
|
+
end
|
20
|
+
rescue => e
|
21
|
+
puts e.errmsg
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](key)
|
25
|
+
@hco[key.to_s]
|
26
|
+
rescue NativeException => x
|
27
|
+
x = x.cause while x.cause
|
28
|
+
x.print_stack_trace
|
29
|
+
rescue => e
|
30
|
+
puts e.errmsg
|
31
|
+
end
|
32
|
+
|
33
|
+
def []=(key,value)
|
34
|
+
@hco[key.to_s] = value
|
35
|
+
rescue NativeException => x
|
36
|
+
x = x.cause while x.cause
|
37
|
+
x.print_stack_trace
|
38
|
+
rescue => e
|
39
|
+
puts e.errmsg
|
40
|
+
end
|
41
|
+
|
42
|
+
def keys(predicate = nil)
|
43
|
+
@hco.key_set(prepare_predicate(predicate)).map
|
44
|
+
rescue NativeException => x
|
45
|
+
x = x.cause while x.cause
|
46
|
+
x.print_stack_trace
|
47
|
+
rescue => e
|
48
|
+
puts e.errmsg
|
49
|
+
end
|
50
|
+
|
51
|
+
def values(predicate = nil)
|
52
|
+
@hco.values(prepare_predicate(predicate)).map
|
53
|
+
rescue NativeException => x
|
54
|
+
x = x.cause while x.cause
|
55
|
+
x.print_stack_trace
|
56
|
+
rescue => e
|
57
|
+
puts e.errmsg
|
58
|
+
end
|
59
|
+
|
60
|
+
def local_keys(predicate = nil)
|
61
|
+
@hco.local_key_set(prepare_predicate(predicate)).map
|
62
|
+
rescue NativeException => x
|
63
|
+
x = x.cause while x.cause
|
64
|
+
x.print_stack_trace
|
65
|
+
rescue => e
|
66
|
+
puts e.errmsg
|
67
|
+
end
|
68
|
+
|
69
|
+
def local_stats
|
70
|
+
lsm = @hco.local_map_stats
|
71
|
+
{ :backup_count => lsm.backup_entry_count, :backup_memory => lsm.backup_entry_memory_cost,
|
72
|
+
:created => lsm.creation_time, :last_accessed => lsm.last_access_time, }
|
73
|
+
rescue => e
|
74
|
+
puts e.errmsg
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def prepare_predicate(predicate)
|
80
|
+
return if predicate.nil?
|
81
|
+
case predicate
|
82
|
+
when String
|
83
|
+
SqlPredicate.new predicate
|
84
|
+
when Hash
|
85
|
+
SqlPredicate.new predicate.map{|k,v| "#{k} = #{v}"}.join(' AND ')
|
86
|
+
when SqlPredicate
|
87
|
+
predicate
|
88
|
+
else
|
89
|
+
raise "Unknown predicate type"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
RubyHaze::Hash = RubyHaze::Map unless defined? RubyHaze::Hash
|
95
|
+
|
96
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'java'
|
2
|
+
|
3
|
+
module RubyHaze
|
4
|
+
|
5
|
+
MODE = "node" unless defined? MODE
|
6
|
+
GEM_JAR_PATH = File.expand_path(File.dirname(__FILE__) + '/../../jars/hazelcast-1.8.5.jar') unless defined? GEM_JAR_PATH
|
7
|
+
JAR_PATH = ENV['HAZELCAST_JAR_PATH'] || GEM_JAR_PATH unless defined? JAR_PATH
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../lib/rubyhaze')
|
12
|
+
|
data/lib/rubyhaze/set.rb
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../lib/rubyhaze')
|
2
|
+
require 'bitescript'
|
3
|
+
|
4
|
+
module RubyHaze::Stored
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
return if args.empty?
|
12
|
+
hash = args.extract_options!
|
13
|
+
set hash if hash
|
14
|
+
unless args.empty?
|
15
|
+
args.each_with_index do |value, idx|
|
16
|
+
set self.class.field_names[idx], value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def set(*args)
|
22
|
+
if args.size == 2
|
23
|
+
instance_variable_set "@#{args.first}", args.last
|
24
|
+
elsif args.size == 1 && args.first.is_a?(Hash)
|
25
|
+
args.first.each { |k,v| set k, v }
|
26
|
+
else
|
27
|
+
raise "Unknown parameters #{args.inspect} for set"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def get(*args)
|
32
|
+
if args.size == 1
|
33
|
+
instance_variable_get "@#{args.first}"
|
34
|
+
else
|
35
|
+
args.map { |k| get k }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def attributes
|
40
|
+
self.class.field_names.map{ |name| [ name, instance_variable_get("@#{name}") ] }
|
41
|
+
end
|
42
|
+
|
43
|
+
def values
|
44
|
+
self.class.field_names.map{ |name| instance_variable_get("@#{name}") }
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_ary
|
48
|
+
attributes.unshift [ 'class', self.class.name ]
|
49
|
+
end
|
50
|
+
|
51
|
+
def ==(other)
|
52
|
+
return false unless other.respond_to? :to_ary
|
53
|
+
to_ary == other.to_ary
|
54
|
+
end
|
55
|
+
|
56
|
+
def shadow_object
|
57
|
+
self.class.store_java_class.new *values
|
58
|
+
end
|
59
|
+
|
60
|
+
def load_shadow_object(shadow)
|
61
|
+
self.class.field_names.each do |name|
|
62
|
+
instance_variable_set "@#{name}", shadow.send(name)
|
63
|
+
end
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_accessor :uid
|
68
|
+
|
69
|
+
def save
|
70
|
+
@uid ||= String.random_uuid
|
71
|
+
self.class.store[uid] = shadow_object
|
72
|
+
end
|
73
|
+
|
74
|
+
def load
|
75
|
+
raise "Missing uid for load" if uid.nil?
|
76
|
+
found = self.class.store[uid]
|
77
|
+
raise "Record not found" unless found
|
78
|
+
load_shadow_object(found)
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
alias :reload :load
|
83
|
+
|
84
|
+
def to_s
|
85
|
+
"<" + self.class.name + " " + attributes[1..-1].inspect + " >"
|
86
|
+
end
|
87
|
+
|
88
|
+
module ClassMethods
|
89
|
+
|
90
|
+
def create(*args)
|
91
|
+
obj = new(*args)
|
92
|
+
obj.save
|
93
|
+
obj
|
94
|
+
end
|
95
|
+
|
96
|
+
def store
|
97
|
+
@store ||= RubyHaze::Map.new store_java_class_name
|
98
|
+
end
|
99
|
+
|
100
|
+
def fields
|
101
|
+
@fields ||= [
|
102
|
+
[ :uid, :string, {} ]
|
103
|
+
]
|
104
|
+
end
|
105
|
+
|
106
|
+
def field_names() fields.map { |ary| ary[0] } end
|
107
|
+
def field_types() fields.map { |ary| ary[1] } end
|
108
|
+
def field_options() fields.map { |ary| ary[2] } end
|
109
|
+
|
110
|
+
def field(name, type, options = {})
|
111
|
+
puts "Defining :#{name}, :#{type}, #{options.inspect}..."
|
112
|
+
raise "Field [#{name} already defined" if field_names.include?(name)
|
113
|
+
fields << [ name, type, options ]
|
114
|
+
attr_accessor name
|
115
|
+
end
|
116
|
+
|
117
|
+
def field_loads
|
118
|
+
{
|
119
|
+
:string => :aload,
|
120
|
+
:int => :iload,
|
121
|
+
:boolean => :iload,
|
122
|
+
:double => :dload,
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
def store_java_class_name
|
127
|
+
'RubyHaze_Shadow__' + name
|
128
|
+
end
|
129
|
+
|
130
|
+
def store_java_class
|
131
|
+
RubyHaze.const_defined?(store_java_class_name) ?
|
132
|
+
RubyHaze.const_get(store_java_class_name) :
|
133
|
+
generate_java_class
|
134
|
+
end
|
135
|
+
|
136
|
+
def generate_java_class
|
137
|
+
builder = BiteScript::FileBuilder.new store_java_class_name + '.class'
|
138
|
+
class_dsl = []
|
139
|
+
class_dsl << %{public_class "#{store_java_class_name}", object, Java::JavaIo::Serializable do}
|
140
|
+
fields.each do |name, type, options|
|
141
|
+
class_dsl << %{ public_field :#{name}, send(:#{type})}
|
142
|
+
end
|
143
|
+
class_dsl << %{ public_constructor [], #{field_types.map{|x| x.to_s}.join(', ')} do}
|
144
|
+
class_dsl << %{ aload 0}
|
145
|
+
class_dsl << %{ invokespecial object, "<init>", [void]}
|
146
|
+
index = 1
|
147
|
+
fields.each do |name, type, options|
|
148
|
+
class_dsl << %{ aload 0}
|
149
|
+
class_dsl << %{ #{field_loads[type]} #{index}}
|
150
|
+
index += 1
|
151
|
+
class_dsl << %{ putfield this, :#{name}, send(:#{type})}
|
152
|
+
end
|
153
|
+
class_dsl << %{ returnvoid}
|
154
|
+
class_dsl << %{ end}
|
155
|
+
class_dsl << %{end}
|
156
|
+
class_dsl = class_dsl.join("\n")
|
157
|
+
if $DEBUG
|
158
|
+
FileUtils.mkdir_p RubyHaze::TMP_PATH
|
159
|
+
filename = RubyHaze::TMP_PATH + '/' + store_java_class_name + '.bc'
|
160
|
+
File.open(filename, 'w') { |file| file.write class_dsl }
|
161
|
+
end
|
162
|
+
builder.instance_eval class_dsl, __FILE__, __LINE__
|
163
|
+
builder.generate do |builder_filename, class_builder|
|
164
|
+
bytes = class_builder.generate
|
165
|
+
klass = JRuby.runtime.jruby_class_loader.define_class store_java_class_name, bytes.to_java_bytes
|
166
|
+
if $DEBUG
|
167
|
+
filename = RubyHaze::TMP_PATH + '/' + builder_filename
|
168
|
+
File.open(filename, 'w') { |file| file.write class_builder.generate }
|
169
|
+
end
|
170
|
+
RubyHaze.const_set store_java_class_name, JavaUtilities.get_proxy_class(klass.name)
|
171
|
+
end
|
172
|
+
RubyHaze.const_get store_java_class_name
|
173
|
+
end
|
174
|
+
|
175
|
+
def find(predicate)
|
176
|
+
store.values(predicate).map { |shadow| new.load_shadow_object shadow }
|
177
|
+
end
|
178
|
+
|
179
|
+
def find_uids(predicate)
|
180
|
+
store.keys(predicate)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class RubyHaze::FakeStore
|
2
|
+
|
3
|
+
java_import 'com.hazelcast.core.MapStore'
|
4
|
+
|
5
|
+
include MapStore
|
6
|
+
|
7
|
+
def delete(key)
|
8
|
+
puts "[FakeStore] Deleting key [#{key}]"
|
9
|
+
end
|
10
|
+
|
11
|
+
def delete_all(keys)
|
12
|
+
puts "[FakeStore] Deleting #{keys.size} keys"
|
13
|
+
keys.each { |key| delete key }
|
14
|
+
end
|
15
|
+
|
16
|
+
def store(key, value)
|
17
|
+
puts "[FakeStore] Storing key [#{key}] value [#{value}]"
|
18
|
+
end
|
19
|
+
|
20
|
+
def store_all(map)
|
21
|
+
puts "[FakeStore] Storing #{map.size} key/values"
|
22
|
+
map.each { |key, value| store key, value }
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../lib/rubyhaze')
|
2
|
+
|
3
|
+
class RubyHaze::Topic
|
4
|
+
|
5
|
+
include RubyHaze::BaseMixin
|
6
|
+
|
7
|
+
java_import 'com.hazelcast.core.MessageListener'
|
8
|
+
|
9
|
+
def initialize(name)
|
10
|
+
@name = name.to_s
|
11
|
+
@hco = Hazelcast.get_topic @name
|
12
|
+
end
|
13
|
+
|
14
|
+
def on_message(&blk)
|
15
|
+
klass = Class.new
|
16
|
+
klass.send :include, MessageListener
|
17
|
+
klass.send :define_method, :on_message, &blk
|
18
|
+
@hco.add_message_listener klass.new
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/rubyhaze.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'java'
|
2
|
+
|
3
|
+
module RubyHaze
|
4
|
+
|
5
|
+
class Exception < StandardError; end
|
6
|
+
|
7
|
+
ROOT = File.expand_path File.join(File.dirname(__FILE__), '..') unless defined? ROOT
|
8
|
+
LIB_PATH = ROOT + "/lib/rubyhaze" unless defined? LIB_PATH
|
9
|
+
TMP_PATH = (ENV['RUBYHAZE_TMP_PATH'] || ROOT + '/tmp')
|
10
|
+
|
11
|
+
$CLASSPATH << TMP_PATH
|
12
|
+
|
13
|
+
unless defined? MODE
|
14
|
+
require LIB_PATH + '/' + (ENV['RUBYHAZE_MODE'] || 'node')
|
15
|
+
end
|
16
|
+
|
17
|
+
puts ">> Loading Hazelcast #{MODE} library..."
|
18
|
+
if File.file?(JAR_PATH)
|
19
|
+
require JAR_PATH
|
20
|
+
java_import 'com.hazelcast.core.Hazelcast'
|
21
|
+
Hazelcast.get_cluster
|
22
|
+
puts ">> ... loaded!"
|
23
|
+
else
|
24
|
+
puts "ERROR! Could not find the Hazelcast JAR file in [#{JAR_PATH}]."
|
25
|
+
abort
|
26
|
+
end
|
27
|
+
|
28
|
+
%w{core_ext base_mixin map multi_map set list queue topic lock stored}.each do |name|
|
29
|
+
require LIB_PATH + '/' + name
|
30
|
+
end
|
31
|
+
|
32
|
+
class << self
|
33
|
+
|
34
|
+
java_import 'com.hazelcast.core.Hazelcast'
|
35
|
+
|
36
|
+
def instances
|
37
|
+
Hazelcast.get_instances
|
38
|
+
end
|
39
|
+
|
40
|
+
def cluster
|
41
|
+
Hazelcast.get_cluster
|
42
|
+
end
|
43
|
+
|
44
|
+
def config
|
45
|
+
Hazelcast.get_config
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
RH = RubyHaze unless defined? RH
|
data/test/test_stored.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/rubyhaze')
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class Foo
|
5
|
+
include RubyHaze::Stored
|
6
|
+
field :name, :string
|
7
|
+
field :age, :int
|
8
|
+
end unless defined? Foo
|
9
|
+
|
10
|
+
class TestRubyHazeStoredClassMethods < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def test_right_store
|
13
|
+
store = Foo.store
|
14
|
+
assert_equal store.class.name, "RubyHaze::Map"
|
15
|
+
assert_equal store.name, "RubyHaze_Shadow__Foo"
|
16
|
+
assert_equal store.name, RubyHaze::Map.new("RubyHaze_Shadow__Foo").name
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_right_fields
|
20
|
+
fields = Foo.fields
|
21
|
+
assert_equal fields, [[:uid, :string, {}], [:name, :string, {}], [:age, :int, {}]]
|
22
|
+
assert_equal Foo.field_names, [:uid, :name, :age]
|
23
|
+
assert_equal Foo.field_types, [:string, :string, :int]
|
24
|
+
assert_equal Foo.field_options, [{}, {}, {}]
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_right_shadow_class
|
28
|
+
assert_equal Foo.store_java_class_name, "RubyHaze_Shadow__Foo"
|
29
|
+
assert_equal Foo.store_java_class.name, "Java::Default::RubyHaze_Shadow__Foo"
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
class TestRubyHazeStoredStorage < Test::Unit::TestCase
|
36
|
+
|
37
|
+
def test_store_reload_objects
|
38
|
+
Foo.store.clear
|
39
|
+
assert_equal Foo.store.size, 0
|
40
|
+
@a = Foo.create :name => "Leonardo", :age => 65
|
41
|
+
assert_equal Foo.store.size, 1
|
42
|
+
@b = Foo.create :name => "Michelangelo", :age => 45
|
43
|
+
assert_equal Foo.store.size, 2
|
44
|
+
@b.age = 47
|
45
|
+
@b.reload
|
46
|
+
assert_equal Foo.store.size, 2
|
47
|
+
assert_equal @b.age, 45
|
48
|
+
Foo.store.clear
|
49
|
+
assert_equal Foo.store.size, 0
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_find_through_predicates
|
53
|
+
Foo.store.clear
|
54
|
+
@a = Foo.create :name => "Leonardo", :age => 65
|
55
|
+
@b = Foo.create :name => "Michelangelo", :age => 45
|
56
|
+
@c = Foo.create :name => "Raffaello", :age => 32
|
57
|
+
|
58
|
+
res = Foo.find 'age < 40'
|
59
|
+
assert_equal res.size, 1
|
60
|
+
assert_equal res.first, @c
|
61
|
+
assert_equal res.first.name, @c.name
|
62
|
+
|
63
|
+
res = Foo.find 'age BETWEEN 40 AND 50'
|
64
|
+
assert_equal res.size, 1
|
65
|
+
assert_equal res.first, @b
|
66
|
+
assert_equal res.first.name, @b.name
|
67
|
+
|
68
|
+
res = Foo.find "name LIKE 'Leo%'"
|
69
|
+
assert_equal res.size, 1
|
70
|
+
assert_equal res.first, @a
|
71
|
+
assert_equal res.first.name, @a.name
|
72
|
+
|
73
|
+
# res = Foo.find "age IN (32, 65)"
|
74
|
+
# assert_equal res.size, 2
|
75
|
+
# names = res.map{|x| x.name }.sort
|
76
|
+
# assert_equal names.first, @a.name
|
77
|
+
# assert_equal names.last, @b.name
|
78
|
+
|
79
|
+
res = Foo.find "age < 40 AND name LIKE '%el%'"
|
80
|
+
assert_equal res.size, 1
|
81
|
+
assert_equal res.first, @c
|
82
|
+
assert_equal res.first.name, @c.name
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rubyhaze
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: jruby
|
11
|
+
authors:
|
12
|
+
- Adrian Madrid
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-08-05 00:00:00 -06:00
|
18
|
+
default_executable: rh_console
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: bitescript
|
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: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
description: JRuby convenience library to connect with Hazelcast
|
33
|
+
email: aemadrid@gmail.com
|
34
|
+
executables:
|
35
|
+
- rh_console
|
36
|
+
extensions: []
|
37
|
+
|
38
|
+
extra_rdoc_files:
|
39
|
+
- LICENSE
|
40
|
+
- README.rdoc
|
41
|
+
files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
44
|
+
- Rakefile
|
45
|
+
- VERSION
|
46
|
+
- bin/rh_console
|
47
|
+
- lib/rubyhaze.rb
|
48
|
+
- lib/rubyhaze/base_mixin.rb
|
49
|
+
- lib/rubyhaze/client.rb
|
50
|
+
- lib/rubyhaze/core_ext.rb
|
51
|
+
- lib/rubyhaze/list.rb
|
52
|
+
- lib/rubyhaze/lock.rb
|
53
|
+
- lib/rubyhaze/map.rb
|
54
|
+
- lib/rubyhaze/multi_map.rb
|
55
|
+
- lib/rubyhaze/node.rb
|
56
|
+
- lib/rubyhaze/queue.rb
|
57
|
+
- lib/rubyhaze/set.rb
|
58
|
+
- lib/rubyhaze/stored.rb
|
59
|
+
- lib/rubyhaze/stores/fake_store.rb
|
60
|
+
- lib/rubyhaze/topic.rb
|
61
|
+
- test/test_stored.rb
|
62
|
+
has_rdoc: true
|
63
|
+
homepage: http://github.com/aemadrid/rubyhaze
|
64
|
+
licenses: []
|
65
|
+
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options:
|
68
|
+
- --charset=UTF-8
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.3.6
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: JRuby convenience library to connect with Hazelcast
|
92
|
+
test_files:
|
93
|
+
- test/test_stored.rb
|