Permalink
Browse files

more work

  • Loading branch information...
daveray committed Oct 9, 2011
1 parent d9e43ce commit deeb29d3676653b39107090f634e364bfb26f235
Showing with 322 additions and 92 deletions.
  1. +76 −0 README.md
  2. +9 −0 Rakefile
  3. +1 −4 familiar.gemspec
  4. +96 −16 lib/familiar.rb
  5. +0 −16 lib/familiar/atom.rb
  6. +0 −28 lib/familiar/fn.rb
  7. +0 −12 lib/familiar/ref.rb
  8. +0 −16 lib/familiar/seq.rb
  9. +34 −0 test.rb
  10. +106 −0 test/test_familiar.rb
View
@@ -0,0 +1,76 @@
+Want to use Clojure's persistent, lazy data structures and concurrency primitives, but afraid of parentheses? Try it from Ruby.
+
+Use the Clojure runtime from Ruby, JRuby in particular.
+
+# Usage
+
+ require 'familiar'
+
+Functions in `clojure.core` are mapped to the `Familiar` module, replacing hyphens with underscores:
+
+ (clojure.core/hash-map "a" 1 "b" 2)
+
+becomes:
+
+ Familiar.hash_map "a", 1, "b" 2
+
+Some functions have additional Ruby sugar. See below.
+
+# Persistent data structures
+
+
+ # Create a vector
+ v = Familiar.vector 1, 2, 3, 4
+ v.nth 2
+ w = v.assoc 2 "hi"
+
+ # Create a map
+ v = Familiar.hash_map "a", 1, "b", 2
+ w = v.assoc "c", 3
+ w["c"] -> 3
+
+# Atoms
+
+ a = Familiar.atom(99)
+ a.swap! |v|
+ v + 1
+ end
+ a.deref -> 100
+ a.reset! 101
+ a.deref -> 101
+
+# Refs and STM
+
+ r = Familiar.ref(99)
+ Familiar.dosync do
+ r.alter {|v| v + 1}
+ end
+ r.deref -> 100
+
+# Agents
+
+ a = Familiar.agent(99)
+ a.send_ do |v|
+ java.lang.Thread.sleep 10000
+ v + 1
+ end
+ a.deref -> 99
+ # ... 10 seconds later ...
+ a.deref -> 100
+
+Note that it's `send_`, not `send` since that conflicts with the built-in Ruby method with that name.
+
+# Sequences
+
+Here's how you can make a lazy sequence
+
+ def my_range(n)
+ Familiar.lazy_seq do
+ if n == 0
+ nil
+ else
+ Familiar.cons n, my_range(n - 1)
+ end
+ end
+ end
+
View
@@ -0,0 +1,9 @@
+require 'rake/testtask'
+
+Rake::TestTask.new do |t|
+ t.libs << 'test'
+end
+
+desc "Run tests"
+task :default => :test
+
View
@@ -1,3 +1,4 @@
+# $ jgem build familiar.gemspec && jgem install ./familiar-0.0.0.gem
Gem::Specification.new do |s|
s.name = 'familiar'
s.version = '0.0.0'
@@ -7,10 +8,6 @@ Gem::Specification.new do |s|
s.authors = ["Dave Ray"]
s.email = 'daveray@gmail.com'
s.files = ["lib/familiar.rb",
- "lib/familiar/fn.rb",
- "lib/familiar/atom.rb",
- "lib/familiar/ref.rb",
- "lib/familiar/seq.rb",
"lib/clojure-1.3.0.jar"]
s.homepage = 'http://rubygems.org/gems/familiar'
end
View
@@ -1,32 +1,112 @@
require "java"
require "clojure-1.3.0.jar"
-require 'familiar/fn'
-require 'familiar/atom'
-require 'familiar/ref'
-require 'familiar/seq'
-
module Familiar
- def self.future(&code)
- Java::clojure.lang.Agent.soloExecutor.submit(Callable.new(code))
+ # map some_func to clojure.core/some-func
+ def self.method_missing(meth, *args, &block)
+ #puts "Missing #{meth}"
+ m = Java::clojure.lang.RT.var("clojure.core", meth.to_s.gsub("_", "-"))
+ if m.is_bound?
+ m.invoke(*args)
+ else
+ super
+ end
+ end
+
+ #############################################################################
+ # Functions
+
+ class Callable
+ include Java::java.util.concurrent.Callable
+ def initialize(callable)
+ @callable = callable
+ end
+
+ def call
+ @callable.call
+ end
end
- def self.print(v)
- puts(Java::clojure.lang.RT.print_string(v))
+ class Fn < Java::clojure.lang.AFn
+ def initialize &block
+ @block = block
+ end
+
+ def invoke(*args)
+ @block.call *args
+ end
end
-
- def self.hash_map(*args)
- Java::clojure.lang.RT.map(*args)
+ def self.fn(p)
+ Fn.new &p
end
- def self.hash_set(*args)
- Java::clojure.lang.RT.set(*args)
+ #############################################################################
+ # Seqs
+
+ def self.lazy_seq(&code)
+ Java::clojure.lang.LazySeq.new(Familiar.fn(code))
end
- def self.vector(*args)
- Java::clojure.lang.RT.vector(*args)
+ #############################################################################
+ # Atoms
+
+ def self.atom?(v)
+ v.is_a? Java::clojure.lang.Atom
+ end
+
+ class Java::ClojureLang::Atom
+ def swap!(&code)
+ swap(Familiar.fn(code))
+ end
+
+ def reset!(v)
+ reset(v)
+ end
+ end
+
+ #############################################################################
+ # Refs and STM
+
+ def self.dosync(&code)
+ Java::clojure.lang.LockingTransaction.runInTransaction(Callable.new(code))
+ end
+
+ class Java::ClojureLang::Ref
+ def alter(&code)
+ java_send :alter,
+ [Java::clojure.lang.IFn.java_class,
+ Java::clojure.lang.ISeq.java_class],
+ Familiar.fn(code),
+ nil
+ end
+
+ def commute(&code)
+ java_send :commute,
+ [Java::clojure.lang.IFn.java_class,
+ Java::clojure.lang.ISeq.java_class],
+ Familiar.fn(code),
+ nil
+ end
+ end
+
+ #############################################################################
+ # Agents
+
+ class Java::ClojureLang::Agent
+ def send_(&code)
+ Familiar.send(self, Familiar.fn(code))
+ end
+
+ def send_off(&code)
+ Familiar.send_off(self, Familiar.fn(code))
+ end
+ end
+
+
+ def self.future(&code)
+ Java::clojure.lang.Agent.soloExecutor.submit(Callable.new(code))
end
end
View
@@ -1,16 +0,0 @@
-module Familiar
-
- def self.atom(v)
- Java::clojure.lang.Atom.new v
- end
-
- class Java::ClojureLang::Atom
- def swap!(&code)
- swap(Familiar.fn(code))
- end
- def reset!(v)
- reset(v)
- end
- end
-
-end
View
@@ -1,28 +0,0 @@
-module Familiar
-
- class Callable
- include Java::java.util.concurrent.Callable
- def initialize(callable)
- @callable = callable
- end
-
- def call
- @callable.call
- end
- end
-
- class Fn < Java::clojure.lang.AFn
- def initialize &block
- @block = block
- end
-
- def invoke(*args)
- @block.call *args
- end
- end
-
- def self.fn(p)
- Fn.new &p
- end
-
-end
View
@@ -1,12 +0,0 @@
-module Familiar
-
- def self.ref(v)
- Java::clojure.lang.Ref.new v
- end
-
- def self.dosync(&code)
- Java::clojure.lang.LockingTransaction.runInTransaction(Callable.new(code))
- end
-
-
-end
View
@@ -1,16 +0,0 @@
-module Familiar
-
- def self.seq(coll)
- Java::clojure.lang.RT.seq(coll)
- end
- def self.first(coll)
- Java::clojure.lang.RT.first(coll)
- end
- def self.rest(coll)
- Java::clojure.lang.RT.more(coll)
- end
- def self.next(coll)
- Java::clojure.lang.RT.next(coll)
- end
-
-end
View
34 test.rb
@@ -0,0 +1,34 @@
+require 'rubygems'
+require 'familiar'
+
+clj = Familiar
+clj.fn(lambda {|x,y| puts "HERE!!! #{x + y}"}).invoke(5, 6)
+f = clj.fn(lambda {|x| x + 1 })
+a = clj.atom(0)
+a.swap(f)
+a.swap! do |v|
+ v + 1
+end
+
+(1..10).each do |i|
+ clj.future do
+ (1..1000).each do |j|
+ a.reset!(a.deref + 1)
+ a.swap! do |v|
+ v + 1
+ end
+ a.swap(f)
+ end
+ puts "#{i} done!"
+ end
+end
+Java::java.lang.Thread.sleep 1000
+clj.print a
+
+y = clj.ref("This is a value")
+clj.dosync do
+ puts "HERE I AM IN DOSYNC"
+ y.set "A new value"
+end
+clj.print y
+
Oops, something went wrong.

0 comments on commit deeb29d

Please sign in to comment.