File: simple.rb

package info (click to toggle)
ruby-mustermann19 0.4.3%2Bgit20160621-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 756 kB
  • ctags: 445
  • sloc: ruby: 7,197; makefile: 3
file content (144 lines) | stat: -rw-r--r-- 4,484 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
require 'mustermann'

module Mustermann
  module Router
    # Simple pattern based router that allows matching a string to a given callback.
    #
    # @example
    #   require 'mustermann/router/simple'
    #
    #   router = Mustermann::Router::Simple.new do
    #     on ':name/:sub' do |string, params|
    #       params['sub']
    #     end
    #
    #     on 'foo' do
    #       "bar"
    #     end
    #   end
    #
    #   router.call("foo") # => "bar"
    #   router.call("a/b") # => "b"
    #   router.call("bar") # => nil
    class Simple
      # Default value for when no pattern matches
      attr_accessor :default

      # @example with a default value
      #   require 'mustermann/router/simple'
      #
      #   router = Mustermann::Router::Simple.new(default: 42)
      #   router.on(':name', capture: :digit) { |string| string.to_i }
      #   router.call("23")      # => 23
      #   router.call("example") # => 42
      #
      # @example block with implicit receiver
      #   require 'mustermann/router/simple'
      #
      #   router = Mustermann::Router::Simple.new do
      #     on('/foo') { 'foo' }
      #     on('/bar') { 'bar' }
      #   end
      #
      # @example block with explicit receiver
      #   require 'mustermann/router/simple'
      #
      #   router = Mustermann::Router::Simple.new(type: :rails) do |r|
      #     r.on('/foo') { 'foo' }
      #     r.on('/bar') { 'bar' }
      #   end
      #
      # @param default value to be returned if nothing matches
      # @param options [Hash] pattern options
      # @return [Mustermann::Router::Simple] new router instance
      def initialize(options = {}, &block)
        @options = options
        @map     = []
        @default = @options.delete(:default)

        block.arity == 0 ? instance_eval(&block) : yield(self) if block
      end

      # @example
      #   require 'mustermann/router/simple'
      #
      #   router = Mustermann::Router::Simple.new
      #   router.on(':a/:b') { 42 }
      #   router['foo/bar'] # => <#Proc:...>
      #   router['foo_bar'] # => nil
      #
      # @return [#call, nil] callback for given string, if a pattern matches
      def [](string)
        string = string_for(string) unless string.is_a? String
        @map.detect { |p,v| p === string }[1]
      end

      # @example
      #   require 'mustermann/router/simple'
      #
      #   router = Mustermann::Router::Simple.new
      #   router['/:name'] = proc { |string, params| params['name'] }
      #   router.call('/foo') # => "foo"
      #
      # @param pattern [String, Mustermann::Pattern] matcher
      # @param callback [#call] callback to call on match
      # @see #on
      def []=(pattern, callback)
        on(pattern, call: callback)
      end

      # @example with block
      #   require 'mustermann/router/simple'
      #
      #   router = Mustermann::Router::Simple.new
      #
      #   router.on(':a/:b') { 42 }
      #   router.call('foo/bar') # => 42
      #   router.call('foo_bar') # => nil
      #
      # @example with callback option
      #   require 'mustermann/router/simple'
      #
      #   callback = proc { 42 }
      #   router   = Mustermann::Router::Simple.new
      #
      #   router.on(':a/:b', call: callback)
      #   router.call('foo/bar') # => 42
      #   router.call('foo_bar') # => nil
      #
      # @param patterns [Array<String, Pattern>]
      # @param call [#call] callback object, need to hand in block if missing
      # @param options [Hash] pattern options
      def on(*patterns)
        options = patterns.last.is_a?(Hash) ? patterns.pop : {}
        call    = options.delete(:call) || Proc.new
        patterns.each do |pattern|
          pattern = Mustermann.new(pattern.to_str, @options.merge(options)) if pattern.respond_to? :to_str
          @map << [pattern, call]
        end
      end

      # Finds the matching callback and calls `call` on it with the given input and the params.
      # @return the callback's return value
      def call(input)
        @map.each do |pattern, callback|
          catch(:pass) do
            next unless params = pattern.params(string_for(input))
            return invoke(callback, input, params, pattern)
          end
        end
        @default
      end

      def invoke(callback, input, params, pattern)
        callback.call(input, params)
      end

      def string_for(input)
        input.to_str
      end

      private :invoke, :string_for
    end
  end
end