Class: Rack::Component

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/component.rb,
lib/rack/component/version.rb,
lib/rack/component/memory_cache.rb

Overview

Subclass Rack::Component to compose functional, declarative responses to HTTP requests.

Defined Under Namespace

Classes: MemoryCache

Constant Summary collapse

VERSION =
'0.4.1'.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env = {}) ⇒ Component

Returns a new instance of Component.



89
90
91
# File 'lib/rack/component.rb', line 89

def initialize(env = {})
  @env = env
end

Instance Attribute Details

#envObject (readonly)

Returns the value of attribute env.



119
120
121
# File 'lib/rack/component.rb', line 119

def env
  @env
end

Class Method Details

.cacheObject

Find or initialize a cache store for a Component class. With no configuration, the store is a threadsafe in-memory cache, capped at 100 keys in length to avoid leaking RAM.

Examples:

Use a larger cache instead

class BigComponent < Rack::Component
  cache { MemoryCache.new(length: 2000) }
end


84
85
86
# File 'lib/rack/component.rb', line 84

def cache
  @cache ||= (block_given? ? yield : MemoryCache.new(length: 100))
end

.call(env = {}, &child) ⇒ Object

Instantiate a new component with given env return its rendered output.

Examples:

Render a child block inside an HTML document

class Layout < Rack::Component
  render do |env, &child|
    "      <!DOCTYPE html>\n      <html>\n        <head>\n          <title>\#{env[:title]}</title>\n        </head>\n        <body>\#{child.call}</body>\n      </html>\n    HTML\n  end\nend\n\nLayout.call(title: 'Hello') { \"<h1>Hello from Rack::Component\" } #=>\n# <!DOCTYPE html>\n# <html>\n#   <head>\n#     <title>Hello</title>\n#   </head>\n#   <body><h1>Hello from Rack::Component</h1></body>\n# </html>\n"


33
34
35
# File 'lib/rack/component.rb', line 33

def call(env = {}, &child)
  new(env).call env, &child
end

.flushObject

Forget all memoized calls to this component.



59
60
61
# File 'lib/rack/component.rb', line 59

def flush
  cache.flush
end

.memoized(env = {}, &child) ⇒ Object

Use memoized instead of call to memoize the result of call(env) and return it. Subsequent uses of memoized(env) with the same env will be read from a threadsafe in-memory cache, not computed.

Examples:

Cache a slow network call

class Fetcher < Rack::Component
  render do |env|
    Net::HTTP.get(env[:uri]).to_json
  end
end

Fetcher.memoized(uri: '/slow/api.json')
# ...
# many seconds later...
# => { some: "data" }

Fetcher.memoized(uri: '/slow/api.json') #=> instant! { some: "data" }
Fetcher.memoized(uri: '/other/source.json') #=> slow again!


54
55
56
# File 'lib/rack/component.rb', line 54

def memoized(env = {}, &child)
  cache.fetch(env.hash) { call(env, &child) }
end

.render(&block) ⇒ Object

Use a render block define what a component will do when you call it.

Examples:

Say hello

class Greeter < Rack::Component
  render do |env|
    "Hi, #{env[:name]}"
  end
end

Greeter.call(name: 'Jim') #=> 'Hi, Jim'
Greeter.call(name: 'Bones') #=> 'Hi, Bones'


73
74
75
# File 'lib/rack/component.rb', line 73

def render(&block)
  define_method :call, &block
end

Instance Method Details

#callObject

Out of the box, a Rack::Component just returns whatever env you call it with, or yields with env if you call it with a block. Use a class-level render block when wiriting your Components to override this method with more useful behavior.

Examples:

a useless component

Useless = Class.new(Rack::Component)
Useless.call(number: 1) #=> { number: 1 }
Useless.call(number: 2) #=> { number: 2 }
Useless.call(number: 2) { |env| "the number was #{env[:number]" }
#=> 'the number was 2'

a useful component

class Greeter < Rack::Component
  render do |env|
    "Hi, #{env[:name]}"
  end
end

Greeter.call(name: 'Jim') #=> 'Hi, Jim'
Greeter.call(name: 'Bones') #=> 'Hi, Bones'

See Also:

  • #render


115
116
117
# File 'lib/rack/component.rb', line 115

def call(*)
  block_given? ? yield(env) : env
end