Skip to content

Commit

Permalink
Cleaned up vars stuff a bit. Now can access vars from any namespace, …
Browse files Browse the repository at this point in the history
…not just core.
  • Loading branch information
daveray committed Oct 15, 2011
1 parent 37beaa3 commit cba6374
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 13 deletions.
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,26 @@ Use `Familiar.with` if you don't feel like writing `Familiar` over and over:
end
=> 4950

The `Familiar` module defines `[ns, var]` and `[var]` methods for getting vars directly. This necessary if you want to pass an existing Clojure function to a higher-order function, e.g.

Familiar.with do
map self[:inc], vector(2, 4, 6)
end
=> (3, 5, 7)

# A note on IRB Usage
Most Clojure datastructes (maps, sets, etc) will print out in IRB the same as in the Clojure REPL. The one difference is that lazy sequences will never print out automatically. This is because IRB will always try to print the result of the last expression so something like this:


irb(main):001:0> x = Familiar.repeatedly Familiar.vars.rand
irb(main):001:0> x = Familiar.repeatedly Familiar[:rand]

will lock up IRB as it tries to print the infinite sequence. The Clojure REPL, on the other hand, doesn't try to print the value of a newly `def'd` var so you don't have this problem.

So, to inspect the value of a *finite* lazy sequence in IRB, use the `inspect!` method:

irb(main):001:0> f = Familiar
=> Familiar
irb(main):002:0> x = f.repeatedly f.vars.rand
irb(main):002:0> x = f.repeatedly f[:rand]
=> #<Java::ClojureLang::LazySeq:0x4ab3a5d1>
irb(main):003:0> f.take(2, x)
=> #<Java::ClojureLang::LazySeq:0x7361b0bc>
Expand Down Expand Up @@ -137,14 +144,14 @@ Make a future:
# http://clojuredocs.org/clojure_core/clojure.core/reduce
x = Familiar.with do
reduce fn { |primes,number|
if some(vars.zero?, map(fn {|x| number % x}, primes))
if some(self[:zero?], map(fn {|x| number % x}, primes))
primes
else
conj(primes, number)
end
},
vector(2),
take(100, iterate(vars.inc, 3))
take(100, iterate(self[:inc], 3))
end
Familiar.println x
=> [2 3 5 7 11 13 17 19 23 29 31 ... 67 71 73 79 83 89 97 101]
Expand Down
33 changes: 26 additions & 7 deletions lib/familiar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,52 @@
require "clojure-1.3.0.jar"

module Familiar
# TODO why do I have this again?
module Vars
def self.__lookup(ns, var)
def self.[] (ns, var)
m = Java::clojure.lang.RT.var(ns, var.to_s.gsub("_", "-"))
m.is_bound? ? m : nil
end

def self.method_missing(meth, *args, &block)
__lookup("clojure.core", meth) or super
self["clojure.core", meth] or super
end
end

# Provides access to Clojure vars for when you need to use a Clojure
# var without invoking it.
#
# Example:
# Given a single argument, it's treated as a var in clojure.core. Two
# argument form allows a particular namespace to be referenced.
#
# Examples:
#
# Familiar[:inc]
# => #'clojure.core/inc
#
# Familiar["clojure.set", :union]
# => #'clojure.set/union
#
# Familiar.with do
# filter vars.even?, range(100)
# filter self[:even?], range(100)
# end
#
def self.vars
Familiar::Vars
# Familiar.with do
# require symbol("clojure.set")
# self["clojure.set", :union].invoke(hash_set(1, 2), hash_set(2, 3))
# end
#
def self.[] (ns, var = nil)
if not var
var = ns
ns = "clojure.core"
end
Familiar::Vars[ns, var]
end

def self.method_missing(meth, *args, &block)
#puts "Missing #{meth}"
m = self.vars.send meth
m = self[meth]
if m
m.invoke(*args)
else
Expand Down
12 changes: 10 additions & 2 deletions test/test_familiar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def test_to_s_looks_right
assert Familiar.atom('hi').to_s =~ /^clojure\.lang\.Atom@\h+$/
assert Familiar.ref('hi').to_s =~ /^clojure\.lang\.Ref@\h+$/
assert Familiar.agent('hi').to_s =~ /^clojure\.lang\.Agent@\h+$/
assert Familiar.vars.identity.to_s =~ /^#'clojure\.core\/identity$/
assert Familiar[:identity].to_s =~ /^#'clojure\.core\/identity$/
assert_equal '(1 2 3)', Familiar.cons(1, Familiar.list(2, 3)).to_s
assert_equal '(1 2 3 4)', Familiar.rest(Familiar.range(5)).to_s
end
Expand All @@ -39,7 +39,7 @@ def test_inspect_looks_right
assert Familiar.atom('hi').inspect =~ /^#<Atom@\h+: "hi">$/
assert Familiar.ref('hi').inspect =~ /^#<Ref@\h+: "hi">$/
assert Familiar.agent('hi').inspect =~ /^#<Agent@\h+: "hi">$/
assert Familiar.vars.identity.inspect =~ /^#'clojure\.core\/identity$/
assert Familiar[:identity].inspect =~ /^#'clojure\.core\/identity$/
assert_equal '(1 2 3)', Familiar.cons(1, Familiar.list(2, 3)).inspect
assert_equal '(1 2 3 4)', Familiar.rest(Familiar.range(5)).inspect
end
Expand All @@ -48,6 +48,14 @@ def test_can_force_lazyseqs_with_inspect!
assert_equal '(0 1 2 3)', Familiar.range(4).inspect!
end

def test_can_get_vars_from_other_namespaces
f = Familiar
f.require f.symbol("clojure.set")
union = f["clojure.set", :union]
assert union
assert_equal f.hash_set(1, 2, 3), union.invoke(f.hash_set(1, 2), f.hash_set(3, 2))
end

def test_can_create_a_function_from_a_lambda
f = Familiar.fn(lambda {|x| x * 2 })
assert f.is_a? Java::clojure.lang.IFn
Expand Down

0 comments on commit cba6374

Please sign in to comment.