Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
melborne committed Jul 25, 2011
0 parents commit cff0e14
Show file tree
Hide file tree
Showing 8 changed files with 583 additions and 0 deletions.
41 changes: 41 additions & 0 deletions lib/interpreter_builder.rb
@@ -0,0 +1,41 @@
# encoding: UTF-8
class String
alias _capitalize capitalize
def capitalize
self.split('_').map(&:_capitalize).join
end
end

module InterpreterBuilder
def define_terminal(name, superclass, target_meth, converter=->p{p}, function=true)
define_node(name, superclass, target_meth, function) do |*dir|
converter[*dir].select { |item| yield item, *@attrs }
end
end

def define_nonterminal(name, superclass, target_meth, op, function=true)
define_node(name, superclass, target_meth, function) do |*dir|
f1, *f2 = @attrs.map { |attr| attr.send(target_meth, *dir) }
f1.send(op, *f2)
end
end

def define_node(name, superclass, target_meth, function, &blk)
klass = Class.new(superclass) do
def initialize(*attrs)
*@attrs = attrs
end
define_method(target_meth, &blk)
end
const_set(name.to_s.capitalize, klass)
define_function(name) if function
end

def define_function(name)
self.class_eval {
define_method(name) do |*args|
Module.const_get(name.to_s.capitalize).new(*args)
end
}
end
end
28 changes: 28 additions & 0 deletions sample/calc.rb
@@ -0,0 +1,28 @@
# encoding: UTF-8
require_relative "../lib/interpreter_builder"

class Fixnum
def x
self
end
end

module Calc
extend InterpreterBuilder

class Expression
def x(n)
end
end

nonterminals = {
plus: :+,
minus: :-,
multiple: :*,
divide: :/
}

nonterminals.each do |name, op|
define_nonterminal(name, Expression, :x, op)
end
end
153 changes: 153 additions & 0 deletions sample/census.rb
@@ -0,0 +1,153 @@
# encoding: UTF-8
require_relative "../lib/interpreter_builder"

module Census
extend InterpreterBuilder

Person = Struct.new(:name, :age, :sex, :nationality, :job)

class Expression
def |(other)
Or.new(self, other)
end

def &(other)
And.new(self, other)
end

def evaluate(people)
raise "override this method in the subclass"
end
end

subclasses = {
all: ->person { true },
sex: ->person,sex { person.sex == sex },
age: ->person,age,op { person.age.send(op, age) },
nationality: ->person, nation { person.nationality == nation },
job: ->person,job { person.job == job }
}

subclasses.each do |name, blk|
define_terminal(name, Expression, :evaluate, &blk)
end

nonterminals = {
except: :-,
or: :|,
and: :&
}

nonterminals.each do |name, op|
define_nonterminal(name, Expression, :evaluate, op, false)
end

def except(exp)
Except.new(All.new, exp)
end

# module Interface
# def all
# All.new
# end

# def sex(sex)
# Sex.new(sex)
# end
#
# def age(age, op)
# Age.new(age, op)
# end
#
# def nationality(n)
# Nationality.new(n)
# end
#
# def job(job)
# Job.new(job)
# end
#
# def except(expression1, expression2)
# Except.new(expression1, expression2)
# end
# end

# include Interface

# class All < Expression
# def evaluate(people)
# super { true }
# end
# end

# class Sex < Expression
# def initialize(sex)
# @sex = sex
# end
#
# def evaluate(people)
# super { |p| p.sex == @sex }
# end
# end

# class Age < Expression
# def initialize(age, op)
# @age, @op = age, op
# end
#
# def evaluate(people)
# super { |p| p.age.send(@op, @age) }
# end
# end

# class Nationality < Expression
# def initialize(nationality)
# @nationality = nationality
# end
#
# def evaluate(people)
# super { |p| p.nationality == @nationality }
# end
# end

# class Job < Expression
# def initialize(job)
# @job = job
# end
#
# def evaluate(people)
# super { |p| p.job == @job }
# end
# end

# class Except < Expression
# def initialize(expression1, expression2)
# @expression1 = expression1
# @expression2 = expression2
# end
#
# def evaluate(people)
# @expression1.evaluate(people) - @expression2.evaluate(people)
# end
# end
#
# class Or < Expression
# def initialize(expression1, expression2)
# @expression1, @expression2 = expression1, expression2
# end
#
# def evaluate(people)
# @expression1.evaluate(people) | @expression2.evaluate(people)
# end
# end
#
# class And < Expression
# def initialize(expression1, expression2)
# @expression1, @expression2 = expression1, expression2
# end
#
# def evaluate(people)
# @expression1.evaluate(people) & @expression2.evaluate(people)
# end
# end
end
50 changes: 50 additions & 0 deletions sample/file_finder.rb
@@ -0,0 +1,50 @@
require "find"
require_relative "../lib/interpreter_builder"

module FileSelect
extend InterpreterBuilder
class Expression
def |(other)
Or.new(self, other)
end

def &(other)
And.new(self, other)
end

def evaluate(dir)
files(dir).select { |f| yield f }
end

def files(dir)
dir = File.expand_path(dir)
Find.find(dir).select { |f| File.file? f }
end
end

terminals = {
all: ->f { true },
file_name: ->f, pattern{ File.fnmatch pattern, File.basename(f) },
bigger: ->f, size{ File.size(f) > size },
writable: ->f { File.writable? f }
}

terminals.each do |name, blk|
converter =->dir{ Expression.new.files(dir) }
define_terminal(name, Expression, :evaluate, converter, &blk)
end

nonterminals = {
except: :-,
or: :|,
and: :&
}

nonterminals.each do |name, op|
define_nonterminal(name, Expression, :evaluate, op, false)
end

def except(exp)
Except.new(All.new, exp)
end
end
112 changes: 112 additions & 0 deletions sample/file_finder_original.rb
@@ -0,0 +1,112 @@
# Interpreter Pattern
require "find"

module FileSelect
module Interface
def all
All.new
end

def filename(pattern)
FileName.new(pattern)
end

def bigger(size)
Bigger.new(size)
end

def except(expression)
Not.new(expression)
end

def writable
Writable.new
end
end

class Expression
def |(other)
Or.new(self, other)
end

def &(other)
And.new(self, other)
end

def evaluate(dir)
files(dir).select { |f| yield f }
end

def files(dir)
dir = File.expand_path(dir)
Find.find(dir).each_with_object([]) do |f, mem|
mem << f if File.file?(f)
end
end
end

class All < Expression
def evaluate(dir)
super { true }
end
end

class FileName < Expression
def initialize(pattern)
@pattern = pattern
end

def evaluate(dir)
super { |p| File.fnmatch(@pattern, File.basename(p)) }
end
end

class Bigger < Expression
def initialize(size)
@size = size
end

def evaluate(dir)
super { |p| File.size(p) > @size }
end
end

class Writable < Expression
def evaluate(dir)
super { |p| File.writable? p }
end
end

class Not < Expression
def initialize(expression)
@expression = expression
end

def evaluate(dir)
All.new.evaluate(dir) - @expression.evaluate(dir)
end
end

class Or < Expression
def initialize(expression1, expression2)
@expression1 = expression1
@expression2 = expression2
end

def evaluate(dir)
@expression1.evaluate(dir) | @expression2.evaluate(dir)
end
end

class And < Expression
def initialize(expression1, expression2)
@expression1 = expression1
@expression2 = expression2
end

def evaluate(dir)
@expression1.evaluate(dir) & @expression2.evaluate(dir)
end
end
include Interface
end

0 comments on commit cff0e14

Please sign in to comment.