Class: Qo::Matchers::PatternMatchBlock

Inherits:
Object
  • Object
show all
Defined in:
lib/qo/matchers/pattern_match_block.rb

Overview

Creates a PatternMatch in the style of a block.

This varies from the regular PatternMatch in that all matchers are provided in a more succinct block format:

Qo.match(target) { |m|
  m.when(/^F/, 42) { |(name, age)| "#{name} is #{age}" }
  m.else { "We need a default, right?" }
}

The Public API obscures the fact that the matcher is only called when it is explicitly given an argument to match against. If it is not, it will just return a class waiting for a target, as such:

def get_url(url)
  Net::HTTP.get_response(URI(url)).yield_self(&Qo.match { |m|
    m.when(Net::HTTPSuccess) { |response| response.body.size }
    m.else { |response| raise response.message }
  })
end

get_url('https://github.com/baweaver/qo')
# => 142387
get_url('https://github.com/baweaver/qo/does_not_exist')
# => RuntimeError: Not Found

This is intended for flexibility between singular calls and calls as a paramater to higher order functions like map and yield_self.

This variant was inspired by ideas from Scala, Haskell, and various Ruby libraries dealing with Async and self-yielding blocks. Especially notable were websocket handlers and dry-ruby implementations.

Author:

  • baweaver

Since:

  • 0.3.0

Instance Method Summary collapse

Constructor Details

#initialize {|_self| ... } ⇒ PatternMatchBlock

Returns a new instance of PatternMatchBlock

Yields:

  • (_self)

Yield Parameters:

Since:

  • 0.3.0



46
47
48
49
50
# File 'lib/qo/matchers/pattern_match_block.rb', line 46

def initialize
  @matchers = []

  yield(self)
end

Instance Method Details

#call(target) ⇒ Any | nil

Immediately invokes a PatternMatch

Parameters:

  • target (Any)

    Target to run against and pipe to the associated block if it "matches" any of the GuardBlocks

Returns:

  • (Any | nil)

    Result of the piped block, or nil on a miss

Since:

  • 0.3.0



103
104
105
106
107
108
109
110
111
112
# File 'lib/qo/matchers/pattern_match_block.rb', line 103

def call(target)
  @matchers.each { |guard_block_matcher|
    did_match, match_result = guard_block_matcher.call(target)
    return match_result if did_match
  }

  return @else.call(target) if @else

  nil
end

#else(&fn) ⇒ Proc

Else is the last statement that will be evaluated if all other parts fail. It should be noted that it won't magically appear, you have to explicitly put an else case in for it to catch on no match unless you want a nil return

Parameters:

  • &fn (Proc)

    Function to call when all other matches have failed

Returns:

  • (Proc)

Raises:

Since:

  • 0.3.0



83
84
85
86
# File 'lib/qo/matchers/pattern_match_block.rb', line 83

def else(&fn)
  raise Qo::Exceptions::MultipleElseClauses if @else
  @else = fn
end

#to_procProc

Proc version of a PatternMatchBlock

Returns:

  • (Proc)

    Any -> Any | nil

Since:

  • 0.3.0



92
93
94
# File 'lib/qo/matchers/pattern_match_block.rb', line 92

def to_proc
  Proc.new { |target| self.call(target) }
end

#when(*array_matchers, **keyword_matchers, &fn) ⇒ Array[GuardBlockMatcher]

Creates a match case. This is the exact same as any other and style match reflected in the public API, except that it's a Guard Block match being performed. That means if the left side matches, the right side function is invoked and that value is returned.

Parameters:

  • *array_matchers (Array[Any])

    Array style matchers

  • **keyword_matchers (Hash[Any, Any])

    Hash style matchers

  • &fn (Proc)

    If matched, this function will be called

Returns:

  • (Array[GuardBlockMatcher])

    The return of this method should not be directly depended on, but will provide all matchers currently present. This will likely be left for ease of debugging later.

Since:

  • 0.3.0



70
71
72
# File 'lib/qo/matchers/pattern_match_block.rb', line 70

def when(*array_matchers, **keyword_matchers, &fn)
  @matchers << Qo::Matchers::GuardBlockMatcher.new(*array_matchers, **keyword_matchers, &fn)
end