lib/patternmatching/pattern.rb in patternmatching-0.1.2 vs lib/patternmatching/pattern.rb in patternmatching-0.1.3

- old
+ new

@@ -1,16 +1,20 @@ module PatternMatching + #Private Exception for stop matching class NotMatched < Exception end + #Private class for build structured data class NodeBuilder + private def method_missing(name, *args) Node.new(name, args) end end + #Class for structured data/patterns class Node def initialize(name, children) @name = name @children = children end @@ -21,11 +25,12 @@ def size @children.size end end - class Collector + #Private module for pattern matching and to collect var/val pairs + module Collector def self.walk(source, target, list) case source when Symbol list[source] = target when Node @@ -97,10 +102,11 @@ raise NotMatched.new end end end + #Private class to run pattern matching class MatchExec def self.exec_as(target, patterns, receiver) patterns.each do |pair| pattern = pair.keys[0] action = pair[pattern] @@ -113,10 +119,12 @@ end return ExecuteAs.new(args, receiver).call(&action) end end + #Private class enabling to use the name of symbols in patterns + #like a local variables in action blocks class ExecuteAs def initialize(args, receiver) @this = receiver @args = args end @@ -139,10 +147,11 @@ result end end end + #Private class for collecting pattern/action fragments class PatternFragments def initialize(patterns) @patterns = patterns end def seems(pattern, &action) @@ -155,143 +164,81 @@ def something proc {_} end end - # DSL element - def build(&block) - NodeBuilder.new.instance_eval(&block) - end - def self.build(&block) - NodeBuilder.new.instance_eval(&block) - end - def make(target, &block) - patterns = [] - PatternFragments.new(patterns).instance_eval(&block) - MatchExec.exec_as(target, patterns, self) - end - def as(&block) - block - end - def something - proc {_} - end - def func(name, &block) - pattern_name = ("@_pattern_" + name.to_s ).to_sym - unless method_defined?(name) + # Domain Specific Language style methods + module DSL + #Build structured data + #=== Usage + # build {[foo(bar, 100), foo(buzz, "abc")]} + def build(&block) + NodeBuilder.new.instance_eval(&block) + end + + #Build structured data + #=== Usage + # PatternMatching.build {[foo(bar, 100), foo(buzz, "abc")]} + def self.build(&block) + NodeBuilder.new.instance_eval(&block) + end + + #Do pattern matching + #===Usage + # make TARGET do + # seems as {PATTERN_1} do ACTION_1 end + # seems as {PATTERN_2} do ACTION_2 end + # seems something do ACTION_DEFAULT end + # end + def make(target, &block) patterns = [] - instance_variable_set(pattern_name, patterns) - define_method(name) do |target| - MatchExec.exec_as(target, patterns, self) - end + PatternFragments.new(patterns).instance_eval(&block) + MatchExec.exec_as(target, patterns, self) end - patterns = instance_variable_get(pattern_name) - fragments = PatternFragments.new(patterns) - if block - fragments.instance_eval(&block) + + #A pattern matches description inside block + #=== Usage + # seems as {some pattern...} do ... end + def as(&block) + block end - fragments - end -end - -=begin -# If installed from rubygems -require "rubygems" -gem "patternmatching" - -# for use -require "patternmatching" - - -# partial func example -class Calc - extend PatternMatching - - func(:calcm).seems as {plus(:a, :b)} do - calcm(a) + calcm(b) - end - func(:calcm).seems as {mul(:a, :b)} do - calcm(a) * calcm(b) - end - func(:calcm).seems as {:value} do - value - end -end - -val = 200 -code = PatternMatching.build {plus(mul(100, 100), val)} -p Calc.new.calcm(code) - -# another partial func example -class CalcX - extend PatternMatching - - func(:calcx) do - seems as {plus(:a, :b)} do - calcx(a) + calcx(b) + + #A pattern matches anything + #=== Usage + # seems something do ... end + def something + proc {_} end - seems as {mul(:a, :b)} do - calcx(a) * calcx(b) + + #Define method as partial style + #=== Usage + # func(NAME).seems as {PATTERN_1} do ACTION_1 end + # func(NAME).seems as {PATTERN_2} do ACTION_2 end + # func(NAME).seems something do ACTION_DEFAULT end + # + #or + # + # func NAME do + # seems as {PATTERN_1} do ACTION_1 end + # seems as {PATTERN_2} do ACTION_2 end + # seems something do ACTION_DEFAULT end + # end + # + def func(name, &block) + pattern_name = ("@_pattern_" + name.to_s ).to_sym + unless method_defined?(name) + patterns = [] + instance_variable_set(pattern_name, patterns) + define_method(name) do |target| + MatchExec.exec_as(target, patterns, self) + end + end + patterns = instance_variable_get(pattern_name) + fragments = PatternFragments.new(patterns) + if block + fragments.instance_eval(&block) + end + fragments end end - func(:calcx).seems as {:value} do - value - end + include DSL end - -p CalcX.new.calcx(code) - -# pattern example -include PatternMatching - -def calc(code) - make(code) { - seems as {plus(:a, :b)} do calc(a) + calc(b) end - seems as {mul(:a, :b)} do calc(a) * calc(b) end - seems something do code end - } -end - -p calc(code) - - -# enumerable match example -is = build { exact([1,2,3,4,5]) } -make is do - seems as {exact([:a,:b, _!(:c)])} do - puts a.to_s + ", " + b.to_s + " and " + c.to_s - end - seems something do - puts "not matched" - end -end - -# hash to hash match example -dict = build { {:name => "Taro", :age => 5} } -make dict do - seems as {{:name => :name}} do - puts "He is " + name - end - seems something do - puts "no name" - end -end - -# hash to obj match example -class Person - def initialize(name, age) - @name = name - @age = age - end - attr :name - attr :age -end - -make Person.new("Jiro", 3) do - seems as {{:name => :name}} do - puts "He is " + name - end - seems something do - puts "no name" - end -end -=end