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 module_function # @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 # @return [Ray::Key] A key object representing the key of that name def key(name) Key.new(name) end # @return [Ray::KeyMod] A key_mod object representing the mod combination # of that name def key_mod(name) KeyMod.new(name) end end module DSL class Matcher def initialize(&block) @block = block end # @return [true, false] True if the block this object was created with # returns true when called with obj. def match?(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 [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 describe_matcher(name, &create_block) Matchers.module_eval do define_method(name) do |*args| DSL::Matcher.new(&create_block.call(*args)) end module_function name end end module_function :describe_matcher # @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 :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)] 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_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 class Key def initialize(name) @symbol = name.to_sym end def to_a KEYS[@symbol] end def to_sym @symbol end def ===(other) to_a.include? other end def inspect "key(#{to_sym})" end end class KeyMod def initialize(name) @symbol = name.to_sym end def to_a MOD[@symbol] end def to_sym @symbol end def ===(other) other.is_a?(Integer) && to_a.any? { |const| (o & const) != 0 } end def inspect "key_mod(#{to_sym})" end end end