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



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

#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"


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)

    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



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

def cast(*types, &block)
  caster.register(*types, &block)
  self
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"

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
# File 'lib/mustermann/expander.rb', line 140

def expand(behavior = nil, **values)
  values = caster.cast(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