Class: Mustermann::Expander

Inherits:
Object
  • Object
show all
Defined in:
lib/mustermann/expander.rb

Overview

Allows fine-grained control over pattern expansion.

Examples:

expander = Mustermann::Expander.new(additional_values: :append)
expander << "/users/:user_id"
expander << "/pages/:page_id"

expander.expand(page_id: 58, format: :html5) # => "/pages/58?format=html5"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*patterns, additional_values: :raise, **options) ⇒ Expander

Returns a new instance of Expander

Parameters:

  • patterns (Array<#to_str, Mustermann::Pattern>)

    list of patterns to expand, see #add.

  • additional_values (Symbol)

    behavior when encountering additional values, see #expand.

  • options (Hash)

    used when creating/expanding patterns, see Mustermann.new.


20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/mustermann/expander.rb', line 20

def initialize(*patterns, additional_values: :raise, **options)
  unless additional_values == :raise or additional_values == :ignore or additional_values == :append
    raise ArgumentError, "Illegal value %p for additional_values" % additional_values
  end

  @patterns          = []
  @api_expander      = AST::Expander.new
  @additional_values = additional_values
  @options           = options
  @caster            = Caster.new(Caster::Nil)
  add(*patterns)
end

Instance Attribute Details

#additional_valuesObject (readonly)

Returns the value of attribute additional_values


15
16
17
# File 'lib/mustermann/expander.rb', line 15

def additional_values
  @additional_values
end

#patternsObject (readonly)

Returns the value of attribute patterns


15
16
17
# File 'lib/mustermann/expander.rb', line 15

def patterns
  @patterns
end

Instance Method Details

#==(other) ⇒ Object

See Also:

  • Object#==

153
154
155
156
# File 'lib/mustermann/expander.rb', line 153

def ==(other)
  return false unless other.class == self.class
  other.patterns == patterns and other.additional_values == additional_values
end

#add(*patterns) ⇒ Mustermann::Expander Also known as: <<

Add patterns to expand.

Examples:

expander = Mustermann::Expander.new
expander.add("/:a.jpg", "/:b.png")
expander.expand(a: "pony") # => "/pony.jpg"

Parameters:

  • patterns (Array<#to_str, Mustermann::Pattern>)

    list of to add for expansion, Strings will be compiled to patterns.

Returns:


42
43
44
45
46
47
48
49
50
# File 'lib/mustermann/expander.rb', line 42

def add(*patterns)
  patterns.each do |pattern|
    pattern = Mustermann.new(pattern.to_str, **@options) if pattern.respond_to? :to_str
    raise NotImplementedError, "expanding not supported for #{pattern.class}" unless pattern.respond_to? :to_ast
    @api_expander.add(pattern.to_ast)
    @patterns << pattern
  end
  self
end

#cast {|key, value| ... } ⇒ Mustermann::Expander #cast(*type_matchers) {|key, value| ... } ⇒ Mustermann::Expander #cast(*cast_objects) ⇒ Mustermann::Expander

Register a block as simple hash transformation that runs before expanding the pattern.

Overloads:

  • #cast {|key, value| ... } ⇒ Mustermann::Expander

    Register a block as simple hash transformation that runs before expanding the pattern for all entries.

    Examples:

    casting everything that implements to_param to param

    expander.cast { |o| o.to_param if o.respond_to? :to_param }

    Yields:

    • every key/value pair

    Yield Parameters:

    • key (Symbol)

      omitted if block takes less than 2

    • value (Object)

      omitted if block takes no arguments

    Yield Returns:

    • (Hash{Symbol: Object})

      will replace key/value pair with returned hash

    • (nil, false)

      will keep key/value pair in hash

    • (Object)

      will replace value with returned object

  • #cast(*type_matchers) {|key, value| ... } ⇒ Mustermann::Expander

    Register a block as simple hash transformation that runs before expanding the pattern for certain entries.

    Examples:

    convert user to user_id

    expander = Mustermann::Expander.new('/users/:user_id')
    expand.cast(:user) { |user| { user_id: user.id } }
    
    expand.expand(user: User.current) # => "/users/42"

    convert user, page, image to user_id, page_id, image_id

    expander = Mustermann::Expander.new('/users/:user_id', '/pages/:page_id', '/:image_id.jpg')
    expand.cast(:user, :page, :image) { |key, value| { "#{key}_id".to_sym => value.id } }
    
    expand.expand(user: User.current) # => "/users/42"

    casting to multiple key/value pairs

    expander = Mustermann::Expander.new('/users/:user_id/:image_id.:format')
    expander.cast(:image) { |i| { user_id: i.owner.id, image_id: i.id, format: i.format } }
    
    expander.expander(image: User.current.avatar) # => "/users/42/avatar.jpg"

    casting all ActiveRecord objects to param

    expander.cast(ActiveRecord::Base, &:to_param)

    Parameters:

    • type_matchers (Array<Symbol, Regexp, #===>)

      To identify key/value pairs to match against. Regexps and Symbols match against key, everything else matches against value.

    Yields:

    • every key/value pair

    Yield Parameters:

    • key (Symbol)

      omitted if block takes less than 2

    • value (Object)

      omitted if block takes no arguments

    Yield Returns:

    • (Hash{Symbol: Object})

      will replace key/value pair with returned hash

    • (nil, false)

      will keep key/value pair in hash

    • (Object)

      will replace value with returned object

  • #cast(*cast_objects) ⇒ Mustermann::Expander

    Parameters:

    • cast_objects (Array<#cast>)

      Before expanding, will call #cast on these objects for each key/value pair. Return value will be treated same as block return values described above.

Returns:


110
111
112
113
# File 'lib/mustermann/expander.rb', line 110

def cast(*types, &block)
  caster.register(*types, &block)
  self
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)

See Also:

  • Object#eql?

159
160
161
162
# File 'lib/mustermann/expander.rb', line 159

def eql?(other)
  return false unless other.class == self.class
  other.patterns.eql? patterns and other.additional_values.eql? additional_values
end

#expand(behavior = nil, **values) ⇒ String

Returns expanded string

Examples:

Expanding a pattern

pattern = Mustermann::Expander.new('/:name', '/:name.:ext')
pattern.expand(name: 'hello')             # => "/hello"
pattern.expand(name: 'hello', ext: 'png') # => "/hello.png"

Handling additional values

pattern = Mustermann::Expander.new('/:name', '/:name.:ext')
pattern.expand(:ignore, name: 'hello', ext: 'png', scale: '2x') # => "/hello.png"
pattern.expand(:append, name: 'hello', ext: 'png', scale: '2x') # => "/hello.png?scale=2x"
pattern.expand(:raise,  name: 'hello', ext: 'png', scale: '2x') # raises Mustermann::ExpandError

Setting additional values behavior for the expander object

pattern = Mustermann::Expander.new('/:name', '/:name.:ext', additional_values: :append)
pattern.expand(name: 'hello', ext: 'png', scale: '2x') # => "/hello.png?scale=2x"

Parameters:

  • behavior (Symbol) (defaults to: nil)

    What to do with additional key/value pairs not present in the values hash. Possible options: :raise, :ignore, :append.

  • values (Hash{Symbol: #to_s, Array<#to_s>})

    Values to use for expansion.

Returns:

  • (String)

    expanded string

Raises:

  • (NotImplementedError)

    raised if expand is not supported.

  • (Mustermann::ExpandError)

    raised if a value is missing or unknown


140
141
142
143
144
145
146
147
148
149
150
# File 'lib/mustermann/expander.rb', line 140

def expand(behavior = nil, **values)
  behavior, values = nil, behavior if behavior.is_a? Hash
  values = map_values(values)

  case behavior || additional_values
  when :raise  then @api_expander.expand(values)
  when :ignore then with_rest(values) { |uri, rest| uri }
  when :append then with_rest(values) { |uri, rest| append(uri, rest) }
  else raise ArgumentError, "unknown behavior %p" % behavior
  end
end

#expandable?(values) ⇒ Boolean

Returns:

  • (Boolean)

169
170
171
172
173
# File 'lib/mustermann/expander.rb', line 169

def expandable?(values)
  return false unless values
  expandable, _ = split_values(map_values(values))
  @api_expander.expandable? expandable
end

#hashObject

See Also:

  • Object#hash

165
166
167
# File 'lib/mustermann/expander.rb', line 165

def hash
  patterns.hash + additional_values.hash
end