lib/ray/dsl/matcher.rb in ray-0.0.0.pre2 vs lib/ray/dsl/matcher.rb in ray-0.0.1

- old
+ new

@@ -1,60 +1,166 @@ module Ray # This is the module including all of your matchers as private methods, # allowing you to use them when you call on. - module Matchers; end + module Matchers + # @return [DSL::Matcher] An anonymous matcher, using your block to + # know if the argument matches. + # + # @example + # on :foo, where { |i| i > 10 } do |i| + # puts "#{i} is greater than 10!" + # end + def where(&block) + DSL::Matcher.new { |o| block.call(o) } + end + end module DSL class Matcher - def initialize(target, &block) - @target = Ray.resolve_type(target) + def initialize(&block) @block = block end - # @return [true, false] True if we can match on the object of that class - def can_match_on?(klass) - Ray.resolve_type(klass).ancestors.include? @target - end - # @return [true, false] True if the block this object was created with # returns true when called with obj. def match?(obj) - can_match_on?(obj.class) && @block.call(obj) + @block.call(obj) end alias :=== :match? end end # Describes a new matcher. # # @param [Symbol] name The name you'll use to call your matcher - # @param [Symbol, Module] target the type on which the matcher operates. # @param [Proc] create_block a block called with the arguments of your matcher # method, and returning the block that will be used # to check if the condition is matched. # @example # Ray.describe_matcher(:match, :string) do |regex| # lambda { |str| str =~ regex } # end - def self.describe_matcher(name, target = :anything, &create_block) + def self.describe_matcher(name, &create_block) Matchers.module_eval do - define_method(name) do |*args, &block| - DSL::Matcher.new(target, &create_block.call(*args, &block)) + define_method(name) do |*args| + DSL::Matcher.new(&create_block.call(*args)) end - - private name end end - # This is the universal matcher, using a lambda so you can create - # an anonymous matcher if you only need it once, hence you don't want - # to name it. + # @return [DSL::Matcher] A matcher matching anything (always true) + describe_matcher(:anything) do + lambda { |o| true } + end + + # @return [DSL::Matcher] A matcher matching anything greater than x + # (comparaison using >) + describe_matcher(:more_than) do |x| + lambda { |o| o > x } + end + + # @return [DSL::Matcher] A matcher matching anything that is less than x + # (comparaison using <) + describe_matcher(:less_than) do |x| + lambda { |o| o < x } + end + + # @return [DSL::Matcher] A matcher matching a value close of x. + # @note the maximum and the minimum will only be computed once. # # @example - # on :foo, where { |i| i > 10 } do |i| - # puts "#{i} is greater than 10!" - # end - describe_matcher(:where) do |&block| - lambda { |o| block.call(o) } + # on :win, almost(10_000, 500) do ... end + # on :win, where { |x| x <= 10_000 + 500 && x >= 10_000 - 500 } do ... end + describe_matcher(:almost) do |x, precision| + min, max = (x - precision), (x + precision) + lambda { |o| (o <= max) && (o >= min) } + end + + # @overload inside(x, y[, w, h]) + # @overload inside(rect) + # @overload inside(array) + # + # @return [DSL::Matcher] A matching matching any rect inside the argument. + describe_matcher(:inside) do |*args| + rect = args.size > 1 ? Ray::Rect.new(*args) : args.first.to_rect + lambda { |o| o.inside? rect } + end + + # @overload outside(x, y[, w, h]) + # @overload outside(rect) + # @overload outside(array) + # + # @return [DSL::Matcher] A matching matching any rect outside the argument. + describe_matcher(:outside) do |*args| + rect = args.size > 1 ? Ray::Rect.new(*args) : args.first.to_rect + lambda { |o| o.outside? rect } + end + + # @overload colliding_with(x, y[, w, h]) + # @overload colliding_with(rect) + # @overload colliding_with(array) + # + # @return [DSL::Matcher] A matching matching any rect colliding with the + # argument. + describe_matcher(:colliding_with) do |*args| + rect = args.size > 1 ? Ray::Rect.new(*args) : args.first.to_rect + lambda { |o| o.collide? rect } + end + + KEYS = Ray::Event.constants.inject({}) do |hash, const| + if const =~ /^KEY_(.+)$/ + hash[$1.downcase.to_sym] = [Ray::Event.const_get(const)] + elsif const =~ /^PSP_BUTTON_(.+)$/ + hash["psp_#{$1.downcase.to_sym}".to_sym] = [Ray::Event.const_get(const)] + end + + hash + end + + KEYS[:number] = Ray::Event.constants.select { |c| c =~ /^KEY_\d$/ }.map do |c| + Ray::Event.const_get(c) + end + + KEYS[:number] |= Ray::Event.constants.select { |c| c =~ /^KEY_KP\d$/ }.map do |c| + Ray::Event.const_get(c) + end + + KEYS[:letter] = Ray::Event.constants.select { |c| c =~ /^KEY_[a-z]$/ }.map do |c| + Ray::Event.const_get(c) + end + + KEYS[:function] = Ray::Event.constants.select { |c| c =~ /^KEY_F\d$/ }.map do |c| + Ray::Event.const_get(c) + end + + KEYS[:mod] = [Ray::Event::KEY_RSHIFT, Ray::Event::KEY_LSHIFT, + Ray::Event::KEY_RCTRL, Ray::Event::KEY_LCTRL, + Ray::Event::KEY_RALT, Ray::Event::KEY_LALT, + Ray::Event::KEY_RMETA, Ray::Event::KEY_LMETA, + Ray::Event::KEY_RSUPER, Ray::Event::KEY_LSUPER] + + KEYS[:arrow] = [Ray::Event::KEY_UP, Ray::Event::KEY_DOWN, + Ray::Event::KEY_LEFT, Ray::Event::KEY_RIGHT] + + MOD = Ray::Event.constants.inject({}) do |hash, const| + if const =~ /^KMOD_(.+)$/ + hash[$1.downcase.to_sym] = [Ray::Event.const_get(const)] + end + + hash + end + + # @return [DSL::Matcher] A matcher matching the given key, which is a symbol + # like :space, :a, :b, :number, :letter, :arrow, ... + describe_matcher(:key) do |sym| + ary = KEYS[sym.to_sym] + lambda { |o| ary.include? o } + end + + # @return [DSL::Matcher] A matcher matching the given modifier key + # (:rctrl, :lctrl, :rmeta, :lmeta, ...) + describe_matcher(:key_mod) do |sym| + ary = MOD[sym.to_sym] + lambda { |o| ary.detect { |const| o & const } } end end