Skip to content

Instantly share code, notes, and snippets.

@ackintosh
Created May 31, 2013 12:32
Show Gist options
  • Save ackintosh/5684693 to your computer and use it in GitHub Desktop.
Save ackintosh/5684693 to your computer and use it in GitHub Desktop.
Interpreter pattern in Ruby.
require 'find'
# Interpreter pattern in Ruby
# for search file
class Expression
def |(other)
Or.new(self, other)
end
def &(other)
And.new(self, other)
end
end
class All < Expression
def evaluate(dir)
results = []
Find.find(dir) do |p|
next unless File.file?(p)
results << p
end
results
end
end
class FileName < Expression
def initialize(pattern)
@pattern = pattern
end
def evaluate(dir)
results = []
Find.find(dir) do |p|
next unless File.file?(p)
name = File.basename(p)
results << p if File.fnmatch(@pattern, name)
end
results
end
end
class Bigger < Expression
def initialize(size)
@size = size
end
def evaluate(dir)
results = []
Find.find(dir) do |p|
next unless File.file?(p)
results << p if (File.size(p) > @size)
end
results
end
end
class Writable < Expression
def evaluate(dir)
results = []
Find.find(dir) do |p|
next unless File.file?(p)
results << p if (File.writable?(p))
end
results
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(expr1, expr2)
@expr1 = expr1
@expr2 = expr2
end
def evaluate(dir)
result1 = @expr1.evaluate(dir)
result2 = @expr2.evaluate(dir)
(result1 + result2).sort.uniq
end
end
class And < Expression
def initialize(expr1, expr2)
@expr1 = expr1
@expr2 = expr2
end
def evaluate(dir)
result1 = @expr1.evaluate(dir)
result2 = @expr2.evaluate(dir)
(result1 & result2)
end
end
class Parser
def initialize(text)
@tokens = text.scan(/\(|\)|[\w\.\*]+/)
end
def next_token
@tokens.shift
end
def expression
token = next_token
if token == nil
return nil
elsif token == '('
result = expression
raise 'Expected )' unless next_token == ')'
result
elsif token == 'all'
return All.new
elsif token == 'writable'
return Writable.new
elsif token == 'bigger'
return Bigger.new(next_token.to_i)
elsif token == 'filename'
return FileName.new(next_token)
elsif token == 'not'
return Not.new(expression)
elsif token == 'and'
return And.new(expression, expression)
elsif token == 'or'
return Or.new(expression, expression)
else
raise "Unknown token: #{token}"
end
end
end
def all
All.new
end
def bigger(size)
Bigger.new(size)
end
def name(pattern)
FileName.new(pattern)
end
def except(expression)
Not.new(expression)
end
def writable
Writable.new
end
p (bigger(2000) & except(writable)) | name('*.mp3')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment