Class: Brut::FrontEnd::RequestContext

Inherits:
Object
  • Object
show all
Defined in:
lib/brut/front_end/request_context.rb

Overview

Container for request-specific information that serves as the source of what can be automaticall passed to various methods by Brut.

The intention for this class is to provide access to the 80% of stuff needed by most requests, to alleviate the need to have to dig into env or the Rack request. This also allows arbitrary information to be inserted and made available later.

Several methods of Brut objects take keyword arguments in their initializer or a particular method. The names of those keyword arguments correspond to values that are contained by this class. Thus, if you are creating, say, a Page subclass, and create an initializer for it that accepts the clock: keyword argument, the managed instance of Clock will be passed into it when Brut creates an instance of the class.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env:, session:, flash:, xhr:, body:, host:) ⇒ RequestContext

Create a new RequestContext based on some of the information provided by Rack

Parameters:

  • env (Hash)

    the Rack env object, as available to any middleware

  • session (Brut::FrontEnd::Session)

    the current session, noting that this is the Brut (or your app) session class and not the Rack session.

  • flash (Brut::FrontEnd::Flash)

    the current flash

  • xhr (true|false)

    true if this is an XHR request.

  • body (Object)

    the request.body as provided by Rack

  • host (URI)

    URI the request.host and request.scheme, and request.port as provided by Rack



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/brut/front_end/request_context.rb', line 32

def initialize(env:,session:,flash:,xhr:,body:,host:)
  @hash = {
    env:,
    session:,
    flash:,
    xhr:,
    body:,
    host:,
    csrf_token: Rack::Protection::AuthenticityToken.token(env["rack.session"]),
    clock: Clock.new(session.timezone),
  }
end

Class Method Details

.currentObject



12
13
14
# File 'lib/brut/front_end/request_context.rb', line 12

def self.current
  Thread.current.thread_variable_get(:request_context)
end

.inject(klass, request_params: nil) ⇒ Object

Create an instance of klass injected with the request context.



17
18
19
20
21
22
23
# File 'lib/brut/front_end/request_context.rb', line 17

def self.inject(klass, request_params: nil)
  self.current.then { |request_context|
    request_context.as_constructor_args(klass,request_params:)
  }.then { |constructor_args|
    klass.new(**constructor_args) 
  }
end

Instance Method Details

#[](key) ⇒ Object

Access a given value, returning nil if it's not mapped or is nil

Parameters:

  • key (String|Symbol)

    the value to get

Returns:

  • (Object)

    the mapped value



76
77
78
# File 'lib/brut/front_end/request_context.rb', line 76

def [](key)
  @hash[key.to_sym]
end

#[]=(key, value) ⇒ Object

Set an arbitrary value that can be injected later

Parameters:

  • key (String|Symbol)

    the name of the value. This is converted to a symbol.

  • value (Object)

    the value to map. Should not be nil.



49
50
51
52
# File 'lib/brut/front_end/request_context.rb', line 49

def []=(key,value)
  key = key.to_sym
  @hash[key] = value
end

#as_constructor_args(klass, request_params:, route: nil, form: nil) ⇒ Hash

Based on klass' constructor, returns a Hash that maps all keywords it requires to the values stored in this RequestContext. It is assumed that request_params: contains the query parameters so they can be injected. The Brut::FrontEnd::Routing::Route can also be injected to pass in.

Examples:

class SomeClass
  def initialize(flash:,clock:,date:)
    # ...
  end
end

hash = request_context.as_constructor_args(
  SomeClass,
  request_params: { date: "2024-11-11" }
)

# hash contains:
# {
#   flash: «Flash used to create the RequestContext»,
#   clock: «Clock used to create the RequestContext»,
#   date: "2024-11-11",
# }

object = SomeClass.new(**hash)

Parameters:

  • klass (Class)

    a class that is to be instantiated entirely by the contents of this RequestContext.

  • request_params (Hash)

    Query string parameters provided by Rack.

  • route (Brut::FrontEnd::Routing::Route) (defaults to: nil)

    the route that triggered the request.

  • form (Brut::FrontEnd::Form) (defaults to: nil)

    the form, if available

Returns:

  • (Hash)

    can be splatted to keyword arguments and passed to the constructor of klass

Raises:

  • (ArgumentError)

    if the constructor has any non-keyword arguments, or if any required keyword argument is not present in this RequestContext.



120
121
122
# File 'lib/brut/front_end/request_context.rb', line 120

def as_constructor_args(klass, request_params:, route:nil, form: nil)
  args_for_method(method: klass.instance_method(:initialize), request_params:, form: , route:)
end

#as_method_args(object, method_name, request_params:, form:, route: nil) ⇒ Hash

Based on object' method, returns a Hash that maps all keywords it requires to the values stored in this RequestContext. It is assumed that request_params: contains the query parameters so they can be injected. It is also assumed that form: is the Form that is provided as part of the request. The Brut::FrontEnd::Routing::Route can also be injected to pass in.

Examples:

class SomeClass
  def doit(flash:,clock:,date:)
    # ...
  end
end

object = SomeClass.new

hash = request_context.as_method_args(
  object,
  :doit,
  request_params: { date: "2024-11-11" }
)

# hash contains:
# {
#   flash: «Flash used to create the RequestContext»,
#   clock: «Clock used to create the RequestContext»,
#   date: "2024-11-11",
# }

result = object.doit(**hash)

Parameters:

  • object (Class)

    an object whose method is to be called that requires some of the contents of this RequestContext.

  • method_name (Symbol)

    name of the method that will be called.

  • request_params (Hash)

    Query string parameters provided by Rack. Note that any parameter whose value is the empty string will be coerced to nil.

  • route (Brut::FrontEnd::Routing::Route) (defaults to: nil)

    the route that triggered the request.

  • form (Brut::FrontEnd::Form)

    the form that was submitted with this request. May be nil.

Returns:

  • (Hash)

    can be splatted to keyword arguments and passed to the constructor of klass

Raises:

  • (ArgumentError)

    if the method has any non-keyword arguments, or if any required keyword argument is not present in this RequestContext.



162
163
164
# File 'lib/brut/front_end/request_context.rb', line 162

def as_method_args(object, method_name, request_params:,form:,route:nil)
  args_for_method(method: object.method(method_name), request_params:, form:,route:)
end

#fetch(key) ⇒ Object

Access the given value, raising an exception if it has not been set or if it's nil.

Parameters:

  • key (String|Symbol)

    the value to fetch.

Returns:

  • (Object)

    the mapped value

Raises:

  • (ArgumentError)

    if key was never mapped or maps to nil.



60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/brut/front_end/request_context.rb', line 60

def fetch(key)
  if self.key?(key)
    value = self[key]
    if value
      return value
    else
      raise ArgumentError,"No key '#{key}' in #{self.class}"
    end
  else
    raise ArgumentError,"Key '#{key}' is nil in #{self.class}"
  end
end

#key?(key) ⇒ true|false

Check if a given value has been mapped.

Parameters:

  • key (String|Symbol)

    the value to check

Returns:

  • (true|false)

    if the value is mapped. Note that if nil was injected, this method returns true.



83
84
85
# File 'lib/brut/front_end/request_context.rb', line 83

def key?(key)
  @hash.key?(key.to_sym)
end