Class: RocketIO::Controller

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/rocketio/controller.rb,
lib/rocketio/controller/render.rb,
lib/rocketio/controller/cookies.rb,
lib/rocketio/controller/filters.rb,
lib/rocketio/controller/helpers.rb,
lib/rocketio/controller/sessions.rb,
lib/rocketio/controller/websocket.rb,
lib/rocketio/controller/middleware.rb,
lib/rocketio/controller/authorization.rb,
lib/rocketio/controller/render/engine.rb,
lib/rocketio/controller/render/layout.rb,
lib/rocketio/controller/authentication.rb,
lib/rocketio/controller/error_handlers.rb,
lib/rocketio/controller/render/layouts.rb,
lib/rocketio/controller/render/templates.rb,
lib/rocketio/controller/render/template_vars.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(requested_method = RocketIO::INDEX_METHOD, path_params = RocketIO::EMPTY_ARRAY, env = nil) ⇒ Controller

Returns a new instance of Controller.



18
19
20
21
22
# File 'lib/rocketio/controller.rb', line 18

def initialize requested_method = RocketIO::INDEX_METHOD, path_params = RocketIO::EMPTY_ARRAY, env = nil
  @__requested_method__ = requested_method
  @__path_params_array__ = path_params.freeze
  @__env__ = env if env
end

Class Method Details

.alias_url(path) ⇒ Object

allow controllers to serve multiple URLs

Parameters:

  • path (String || Symbol)


216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/rocketio/controller.rb', line 216

def alias_url path
  path = path.to_s
  path = if path =~ /\A\//
    path
  else
    if superclass == Object
      RocketIO.rootify_path(path)
    else
      RocketIO.rootify_path(superclass.url, path)
    end
  end.freeze
  aliases.push(path)
end

.aliasesObject



230
231
232
# File 'lib/rocketio/controller.rb', line 230

def aliases
  @__aliases__ ||= []
end

.apiObject



122
123
124
# File 'lib/rocketio/controller.rb', line 122

def api
  @__api__
end

.basic_auth(*args, &block) ⇒ Object

Note:

authorization is composable, that’s it, if superclass is protecting :a and current controller is protecting :b method, both :a and :b will be protected in current controller

easily restrict access to controller using basic auth

Examples:

protect all methods on any request methods

basic_auth do |user,pass|
  user == 'admin' && pass == 'super secret password'
end

protect all methods only on POST, PUT and DELETE request methods

basic_auth do |user,pass|
  post? || put? || delete? ?
    user == 'admin' && pass == 'super secret password' :
    true
end

protect only :edit

basic_auth :edit do |user,pass|
  user == 'reader' && pass == 'readPass'
end

Parameters:

  • block (Proc)


30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/rocketio/controller/authentication.rb', line 30

def self.basic_auth *args, &block
  opts = args.last.is_a?(Hash) ? args.pop : {}
  (args.any? ? args.map(&:to_sym) : [:*]).each do |method|
    (@__basic_auth__ ||= {})[method] = {
      class:     Rack::Auth::Basic,
      arguments: [opts[:realm] || RocketIO::DEFAULT_AUTH_REALM].freeze,
      block:     block,
      mock:      RocketIO::HTTP_AUTHORIZATION_MOCKS[:basic]
    }.freeze
  end
  define_basic_auth_methods
end

.call(env) ⇒ Object



267
268
269
270
271
272
273
274
275
# File 'lib/rocketio/controller.rb', line 267

def call env
  path_params = env[RocketIO::PATH_INFO].sub(url, RocketIO::EMPTY_STRING).scan(RocketIO::PATH_SPLITTER)
  method = if path_params.any? && api[path_params[0].to_sym]
    path_params.slice!(0).to_sym
  else
    RocketIO::INDEX_METHOD
  end
  new(method, path_params).call(env)
end

.define_basic_auth_methods(source = self) ⇒ Object



43
44
45
46
47
48
49
50
51
# File 'lib/rocketio/controller/authentication.rb', line 43

def self.define_basic_auth_methods source = self
  prompts = (source.instance_variable_get(:@__basic_auth__) || {}).each_with_object(allocate.basic_auth.dup) do |(m,p),o|
    method = :"__basic_auth__#{m}__"
    api.delete define_method(method, &p[:block])
    o[m] = p.merge(method: method).freeze
  end.freeze
  return if prompts.empty?
  api.delete define_method(:basic_auth) {prompts}
end

.define_digest_auth_methods(source = self) ⇒ Object



96
97
98
99
100
101
102
103
104
# File 'lib/rocketio/controller/authentication.rb', line 96

def self.define_digest_auth_methods source = self
  prompts = (source.instance_variable_get(:@__digest_auth__) || {}).each_with_object(allocate.digest_auth.dup) do |(m,p),o|
    method = :"__digest_auth__#{m}__"
    api.delete define_method(method, &p[:block])
    o[m] = p.merge(method: method).freeze
  end.freeze
  return if prompts.empty?
  api.delete define_method(:digest_auth) {prompts}
end

.define_engine_methods(source = self) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/rocketio/controller/render/engine.rb', line 59

def self.define_engine_methods source = self
  return unless engine = source.instance_variable_get(:@__engine__)
  if Proc === engine
    selfengine = allocate.engine
    api.delete define_method(:__rocketio_engine__, &engine)
    api.delete define_method(:engine) {
      engine, *engine_options = __rocketio_engine__
      return selfengine unless engine
      [RocketIO.engine_class(engine), engine_options.freeze].freeze
    }
  else
    api.delete define_method(:engine) {engine}
  end
end

.define_error_handlers_methods(source = self) ⇒ Object



38
39
40
41
42
43
44
45
46
47
# File 'lib/rocketio/controller/error_handlers.rb', line 38

def self.define_error_handlers_methods source = self
  handlers = (source.instance_variable_get(:@__error_handlers__) || {}).each_with_object({}) do |(code,block),o|
    o[code] = :"__#{code}_error_handler__"
    api.delete define_method(o[code], &block)
  end
  handlers.update(allocate.error_handlers)
  return if handlers.empty?
  handlers.freeze
  api.delete define_method(:error_handlers) {handlers}
end

.define_layout(name, file: nil, &block) ⇒ Object

Note:

files will be searched relative to controller’s dirname, that’s it, the folder controller was defined in and operates from.

Note:

when searching for file multiple extensions will be tried, that’s it, all extensions controller’s engine actually supports.

Note:

controllers that inherits named layouts will always search for files in own dirname. controllers that inherits :file layouts will search files in the original controller’s dirname.

if only name given it will search for a file with same name in controller’s dirname.

if file name differs from layout name pass it as :file option. file path should be relative to controller’s dirname. also a block accepted for :file option. the block will be executed at controllers’s instance level and should return path to layout file. file name should NOT include extension.

if a block given NO file will be searched and returned value will be used as layout.

Examples:

define :master layout.

./master.erb file will be used

define_layout :master

define :master layout.

../layouts/master.erb file will be used

define_layout :master, file: '../layouts/master'

define :master layout.

./admin file to be used when user logged in and ./user otherwise

define_layout :master, file: -> {user? ? 'admin' : 'user'}

define :master layout using a block that returns the layout string.

no file will be used.

define_layout(:master) do
  layout = Layouts.find_by(id: params[:layout_id]) || halt(400, 'Template not found')
  layout.source
end

Parameters:

  • name
  • file (defaults to: nil)
  • block


50
51
52
53
54
# File 'lib/rocketio/controller/render/layouts.rb', line 50

def self.define_layout name, file: nil, &block
  file && block && raise(::ArgumentError, 'both file and block given, please use either one')
  (@__layouts__ ||= {})[name.to_sym] = {block: block, root: dirname, file: file, name: name}.freeze
  define_layouts_methods
end

.define_layout_methods(source = self) ⇒ Object



17
18
19
20
21
# File 'lib/rocketio/controller/render/layout.rb', line 17

def self.define_layout_methods source = self
  return unless source.instance_variables.include?(:@__layout__)
  layout = source.instance_variable_get(:@__layout__)
  api.delete define_method(:layout) {layout}
end

.define_layouts_methods(source = self) ⇒ Object



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
# File 'lib/rocketio/controller/render/layouts.rb', line 56

def self.define_layouts_methods source = self
  return unless source.instance_variables.include?(:@__layouts__)
  layouts = source.instance_variable_get(:@__layouts__).each_with_object(allocate.layouts.dup) do |(name,setup),o|
    o[name] = :"__#{name}_layout__"
    if setup[:block]
      # block given, do not search for file, use returned value instead
      api.delete define_method(o[name], &setup[:block])
    elsif setup[:file]
      # file given, search the file in original controller dirname
      meth_name = :"__#{name}_layout_file__"
      meth_proc = setup[:file].is_a?(::Proc) ? setup[:file] : -> {setup[:file]}
      api.delete define_method(meth_name, &meth_proc)
      api.delete define_method(o[name]) {
        engine, * = resolve_engine
        read_template(find_template(setup[:root], __send__(meth_name), engine))
      }
    else
      # only name given, search for a file with same name in controller's dirname
      api.delete define_method(o[name]) {
        engine, * = resolve_engine
        read_template(find_template(self.dirname, setup[:name], engine))
      }
    end
  end.freeze
  api.delete define_method(:layouts) {layouts}
end

.define_middleware_methods(source = self) ⇒ Object



24
25
26
27
28
# File 'lib/rocketio/controller/middleware.rb', line 24

def self.define_middleware_methods source = self
  middleware = ((source.instance_variable_get(:@__middleware__) || []) + allocate.middleware).uniq.freeze
  return if middleware.empty?
  api.delete define_method(:middleware) {middleware}
end

.define_sessions_methods(source = self) ⇒ Object



56
57
58
59
60
# File 'lib/rocketio/controller/sessions.rb', line 56

def self.define_sessions_methods source = self
  return unless source.instance_variables.include?(:@__sessions__)
  sessions = source.instance_variable_get(:@__sessions__)
  api.delete define_method(:sessions) {sessions}
end

.define_template(name, file: nil, &block) ⇒ Object

Note:

files will be searched relative to controller’s dirname, that’s it, the folder controller was defined in and operates from.

Note:

when searching for file multiple extensions will be tried, that’s it, all extensions controller’s engine actually supports.

Note:

controllers that inherits named templates will always search for files in own dirname. controllers that inherits :file templates will search files in the original controller’s dirname.

if only name given it will search for a file with same name in controller’s dirname

if file name differs from template name pass it as :file option. file path should be relative to controller’s dirname. also a block accepted for :file option. the block will be executed at controllers’s instance level and should return path to template file. file name should NOT include extension.

if a block given NO file will be searched and returned value will be used as template.

Examples:

define :items template.

./items.erb file will be used
define_template :items

define :items template.

../shared_templates/items.erb file will be used
define_template :items, file: '../shared_templates/items'

define :items template.

./admin-items.erb file to be used when user logged in and ./items.erb otherwise

define_template :items, file: -> {user? ? 'admin-items' : 'items'}

define :items template using a block that returns the template string.

no file will be used.

define_template(:items) do
  template = Templates.find_by(id: params[:template_id]) || halt(400, 'Template not found')
  template.source
end

Parameters:

  • name
  • file (defaults to: nil)
  • block


48
49
50
51
52
# File 'lib/rocketio/controller/render/templates.rb', line 48

def self.define_template name, file: nil, &block
  file && block && raise(ArgumentError, 'both file and block given, please use either one')
  (@__templates__ ||= {})[name.to_sym] = {block: block, root: dirname, file: file, name: name}.freeze
  define_templates_methods
end

.define_template_var(name, value = nil, &block) ⇒ Object

define variables to be used on templates alongside provided locals.

Parameters:

  • name
  • value (defaults to: nil)


9
10
11
12
13
# File 'lib/rocketio/controller/render/template_vars.rb', line 9

def self.define_template_var name, value = nil, &block
  value || block || raise(ArgumentError, 'A value or a block expected')
  (@__template_vars__ ||= {})[name.to_sym] = (block || value).freeze
  define_template_vars_methods
end

.define_template_vars_methods(source = self) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/rocketio/controller/render/template_vars.rb', line 15

def self.define_template_vars_methods source = self
  return unless source.instance_variables.include?(:@__template_vars__)
  vars = source.instance_variable_get(:@__template_vars__).each_with_object(allocate.__template_vars__.dup) do |(name,value),o|
    o[name] = :"__#{name}_template_var__"
    if value.is_a?(Proc)
      api.delete define_method(o[name], &value)
    else
      api.delete define_method(o[name]) {value}
    end
  end.freeze
  api.delete define_method(:__template_vars__) {vars}
end

.define_templates_methods(source = self) ⇒ Object



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
# File 'lib/rocketio/controller/render/templates.rb', line 54

def self.define_templates_methods source = self
  return unless source.instance_variables.include?(:@__templates__)
  templates = source.instance_variable_get(:@__templates__).each_with_object(allocate.templates.dup) do |(name,setup),o|
    o[name] = :"__#{name}_template__"
    if setup[:block]
      # block given, do not search for file, use returned value instead
      api.delete define_method(o[name], &setup[:block])
    elsif setup[:file]
      # file given, search the file in original controller dirname
      meth_name = :"__#{name}_template_file__"
      meth_proc = setup[:file].is_a?(Proc) ? setup[:file] : -> {setup[:file]}
      api.delete define_method(meth_name, &meth_proc)
      api.delete define_method(o[name]) {
        engine, * = resolve_engine
        read_template(find_template(setup[:root], __send__(meth_name), engine))
      }
    else
      # only name given, search for a file with same name in controller's dirname
      api.delete define_method(o[name]) {
        engine, * = resolve_engine
        read_template(find_template(self.dirname, setup[:name], engine))
      }
    end
  end.freeze
  api.delete define_method(:templates) {templates}
end

.define_token_auth_methods(source = self) ⇒ Object



25
26
27
28
29
# File 'lib/rocketio/controller/authorization.rb', line 25

def self.define_token_auth_methods source = self
  prompts = allocate.token_auth.merge(source.instance_variable_get(:@__token_auth__) || {}).freeze
  return if prompts.empty?
  api.delete define_method(:token_auth) {prompts}
end

.digest_auth(*args, &block) ⇒ Object

easily restrict access to controller using digest auth

Examples:

protect all methods using hashed passwords

# hash the password somewhere in irb:
# ::Digest::MD5.hexdigest 'admin:AccessRestricted:somePassword'
#                   username ^      realm ^       password ^

#=> 9d77d54decc22cdcfb670b7b79ee0ef0

digest_auth :passwords_hashed => true, :realm => 'AccessRestricted' do |user|
  {'admin' => '9d77d54decc22cdcfb670b7b79ee0ef0'}[user]
end

protect all methods using plain passwords

digest_auth do |user|
  {'admin' => 'password'}[user]
end

protect only :create and :edit methods

digest_auth :create, :edit do |user|
  {'admin' => 'password'}[user]
end

Parameters:

  • block (Proc)


81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rocketio/controller/authentication.rb', line 81

def self.digest_auth *args, &block
  opts = args.last.is_a?(Hash) ? args.pop : {}
  opts[:realm]  ||= RocketIO::DEFAULT_AUTH_REALM
  opts[:opaque] ||= opts[:realm]
  (args.any? ? args.map(&:to_sym) : [:*]).each do |method|
    (@__digest_auth__ ||= {})[method] = {
      class:     Rack::Auth::Digest::MD5,
      arguments: [opts].freeze,
      block:     block,
      mock:      RocketIO::HTTP_AUTHORIZATION_MOCKS[:digest]
    }.freeze
  end
  define_digest_auth_methods
end

.dirname(*args) ⇒ Object



263
264
265
# File 'lib/rocketio/controller.rb', line 263

def dirname *args
  ::File.join(@__dirname__, args.map!(&:to_s))
end

.engine(engine = nil, *engine_options, &block) ⇒ Object

Note:

if a block given it will be executed at instance level and result used for engine. To have any options passed at engine initialization the block should return an array having engine as first element and options as consequent elements.

Note:

if given block returns no engine, inherited engine will be used

if no engine set, templates will be rendered using ERB engine. any engine supported by [Tilt](github.com/rtomayko/tilt) can be used. to set engine use symbolized constant name, e.g. :Slim, :Haml engine name is Case Sensitive and there should be a Tilt::ENGINETemplate class defined e.g. ‘engine :Slim` will look for Tilt::SlimTemplate and `engine RDiscount` will look for Tilt::RDiscountTemplate

Examples:

use static engine

engine :Slim

use static engine with options

engine :Slim, pretty_print: true

use dynamically set engine

engine do
  some_condition ? :SomeEngine : AnotherEngine
end

use dynamically set engine with options

engine do
  some_condition ? [:SomeEngine, :opt1, :opt2] : AnotherEngine
end

Search will use ERB when requested by a bot and Slim otherwise


class BaseController < RocketIO
  engine :Slim
end

class Search < BaseController
  engine do
    if request.user_agent =~ /i'm a bot/
      # requested by a bot, using ERB
      :ERB
    end
    # requested by a user, returning no engine for inherited engine to be used
  end
end

Parameters:

  • engine (defaults to: nil)

    engine name.

  • *engine_options

    any arguments to be passed at engine initialization

  • block

    to be executed at instance level



54
55
56
57
# File 'lib/rocketio/controller/render/engine.rb', line 54

def self.engine engine = nil, *engine_options, &block
  @__engine__ = block || [RocketIO.engine_class(engine), engine_options.freeze].freeze
  define_engine_methods
end

.environmentObject



277
# File 'lib/rocketio/controller.rb', line 277

def environment; RocketIO.environment end

.error(code, &block) ⇒ Object

define error handlers

Examples:

define a handler that will process 404 errors

class Pages < RocketIO::Controller

  error 404 do |id|
    "Sorry, looks like item with ID #{id.to_i} does not exists"
  end

  def get id
    item = Item.find_by(id: id) || error(404, id)
  end
end

define a handler that will process fatal errors

class Pages < RocketIO::Controller

  error 500 do |exception|
    "Fatal error occurred: " + html_escape(exception.message)
  end

  def get
    # any exception raised here will be handled by the handler above
  end
end


30
31
32
33
34
35
36
# File 'lib/rocketio/controller/error_handlers.rb', line 30

def self.error code, &block
  code = code.to_i
  code > 0 || raise(ArgumentError, 'Error code should be a number')
  block || raise(ArgumentError, 'block missing')
  (@__error_handlers__ ||= {})[code] = block
  define_error_handlers_methods
end

.import(setup, from:) ⇒ Object

import some config from some controller



127
128
129
# File 'lib/rocketio/controller.rb', line 127

def import setup, from:
  __send__(:"define_#{setup}_methods", from)
end

.inherited(base) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/rocketio/controller.rb', line 131

def inherited base
  # registering a new controller
  RocketIO.controllers.push(base)

  base.instance_variable_set(:@__api__, self.api.dup)

  # new controller inherits all setups from superclass
  base.import :before, from: self
  base.import :around, from: self
  base.import :after,  from: self

  base.import :basic_auth,  from: self
  base.import :digest_auth, from: self
  base.import :token_auth,  from: self

  base.import :error_handlers, from: self
  base.import :middleware,     from: self
  base.import :sessions,       from: self

  base.import :engine,    from: self
  base.import :layout,    from: self
  base.import :layouts,   from: self
  base.import :templates, from: self

  # removing superclass name from new controller name
  path = RocketIO.underscore(base.name.to_s.sub(self.name.to_s + '::', '').gsub('::', '/'))

  # new controller uses for URL its underscored name prefixed by superclass URL
  base.map RocketIO.rootify_path(url, path)

  # setting dirname for new controller
  base.instance_variable_set(:@__dirname__, RocketIO.caller_to_dirname(caller).freeze)
end

.layout(layout) ⇒ Object

Note:

to disable layout set it to false: ‘layout false`

by default templates will be rendered without layout. to make them render inside a layout use ‘layout :layout_name` at class level. to use a layout it should be defined at first (@see define_layout)

Parameters:

  • layout

    name of a defined layout



12
13
14
15
# File 'lib/rocketio/controller/render/layout.rb', line 12

def self.layout layout
  @__layout__ = layout
  define_layout_methods
end

.map(path) ⇒ Object

Note:
Note:

if given URL starts with a slash it will ignore class name and set URL as is

by default controllers will use underscored name for base URL. this method allow to set a custom base URL.

Examples:

Users::Register will listen on /users/register by default

class Users
  class Register < RocketIO

  end
end

make Users::Register to listen on /users/join rather than /users/register


class Users
  class Register < RocketIO
    map :join

  end
end

make Users::Register to listen on /members/join


class Users < RocketIO
  class Register < self
    map '/members/join'

  end
end

Parameters:

  • path (String || Symbol)


199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/rocketio/controller.rb', line 199

def map path
  path = path.to_s
  @__url__ = if path =~ /\A\//
    path
  else
    if superclass == Object
      RocketIO.rootify_path(path)
    else
      RocketIO.rootify_path(superclass.url, path)
    end
  end.freeze
end

.method_added(meth) ⇒ Object



249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/rocketio/controller.rb', line 249

def method_added meth
  return if self == RocketIO::Controller
  return unless public_instance_methods(false).include?(meth)

  parameters = instance_method(meth).parameters

  api[meth] = {
    # api methods should be called with a predetermined set of parameters
    # so setting an appropriate policy for just defined method based on its parameters.
    path_params: RocketIO.path_params(parameters).freeze,
    parameters_policy: RocketIO.parameters_policy(parameters).freeze
  }
end

.sessions(pool = (noargs = true; nil), opts = {}) ⇒ Object

Note:

to disable sessions for some controller set sessions to nil or false

setup sessions. there are 2 setups out of the box:

- cookies
- memcache

you can also use your own setup

Examples:

keep sessions in cookies

sessions :cookies

keep sessions in cookies using custom options

sessions :cookies, secret: 'someSecret', domain: 'some.domain'

keep sessions in memcache

sessions :memcache

use a custom setup, i.e. github.com/migrs/rack-session-mongo

$ gem install rack-session-mongo

require 'rack/session/mongo'

class Pages < RocketIO::Controller
  sessions Rack::Session::Mongo
end

disable sessions for current controller

sessions nil # or false

Parameters:

  • pool (Symbol, Class) (defaults to: (noargs = true; nil))
  • opts (Hash) (defaults to: {})


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/rocketio/controller/sessions.rb', line 36

def self.sessions pool = (noargs = true; nil), opts = {}
  @__sessions__ = if pool.nil? || pool == false
    nil
  else
    if pool == :cookies && opts[:secret].nil?
      opts[:secret] = ::Digest::MD5.hexdigest([Time.now.to_f, rand]*'')
    end
    pool = case pool
    when :cookies
      ::Rack::Session::Cookie
    when :memcache
      ::Rack::Session::Memcache
    else
      pool
    end
    [pool, opts]
  end
  define_sessions_methods
end

.token_auth(*args, &block) ⇒ Object

easily restrict access to controller using token auth

Examples:

simple Token example


class User < RocketIO::Controller
  token_auth { |token| token == 'secret' }
end


14
15
16
17
18
19
20
21
22
23
# File 'lib/rocketio/controller/authorization.rb', line 14

def self.token_auth *args, &block
  opts = args.last.is_a?(Hash) ? args.pop : {}
  (args.any? ? args.map(&:to_sym) : [:*]).each do |method|
    (@__token_auth__ ||= {})[method] = {
      realm: opts[:realm] || RocketIO::DEFAULT_TOKEN_AUTH_REALM.freeze,
      block: block
    }
  end
  define_token_auth_methods
end

.url(*args) ⇒ String

build a URL from given chunks prefixing them with controller’s baseurl

Parameters:

  • *args (Array)

Returns:

  • (String)


239
240
241
242
243
244
245
246
247
# File 'lib/rocketio/controller.rb', line 239

def url *args
  return @__url__ if args.empty?
  query = if args.last.is_a?(Hash)
    RocketIO::QUERY_PREFIX + ::Rack::Utils.build_nested_query(args.pop)
  else
    RocketIO::EMPTY_STRING
  end
  ::File.join(@__url__, args.map!(&:to_s)) + query
end

.use(w = nil, *a, &b) ⇒ Object

Note:

middleware is inheritable

storing Rack middleware to be called when a request handled by controller

Examples:

add a middleware to be used in current controller

and any controllers that inherits from it

class Users < RocketIO::Controller
  use Rack::CommonLogger
end

Parameters:

  • w (Class, Proc) (defaults to: nil)

    a valid Rack middleware that responds to call

  • *a (Array)

    any args to be passed at middleware initialization

  • &b (Proc)

    a block to be yielded at middleware initialization



19
20
21
22
# File 'lib/rocketio/controller/middleware.rb', line 19

def self.use w = nil, *a, &b
  (@__middleware__ ||= []).push(proc {|app| w.new(app, *a, &b)})
  define_middleware_methods
end

Instance Method Details

#__error__(code, *args) ⇒ Object

call defined error handler with given arguments.

Raises:

  • NotImplementedError if no handler defined for given code



66
67
68
69
# File 'lib/rocketio/controller/error_handlers.rb', line 66

def __error__ code, *args
  error_handlers[code] || raise(NotImplementedError, 'No handler defined for %s error' % code.inspect)
  __send__(error_handlers[code], *args)
end

#__template_vars__Object



28
# File 'lib/rocketio/controller/render/template_vars.rb', line 28

def __template_vars__; RocketIO::EMPTY_HASH end

#afterObject



84
# File 'lib/rocketio/controller/filters.rb', line 84

def after;  RocketIO::EMPTY_HASH end

#aroundObject



83
# File 'lib/rocketio/controller/filters.rb', line 83

def around; RocketIO::EMPTY_HASH end

#attachment(filename = nil, disposition = 'attachment') ⇒ Object

Set the Content-Disposition to “attachment” with the specified filename, instructing the user agents to prompt to save.



244
245
246
247
248
249
250
251
# File 'lib/rocketio/controller/helpers.rb', line 244

def attachment(filename = nil, disposition = 'attachment')
  response[RocketIO::CONTENT_DISPOSITION] = disposition.to_s
  if filename
    response[RocketIO::CONTENT_DISPOSITION] << ('; filename="%s"' % File.basename(filename))
    ext = File.extname(filename)
    content_type(ext) unless response[RocketIO::CONTENT_TYPE] or ext.empty?
  end
end

#authentication_required?Boolean

Returns:

  • (Boolean)


126
127
128
129
130
131
# File 'lib/rocketio/controller/authentication.rb', line 126

def authentication_required?
  digest_auth[requested_method] ||
    basic_auth[requested_method] ||
    digest_auth[:*] ||
    basic_auth[:*]
end

#authorization_required?Boolean

Returns:

  • (Boolean)


51
52
53
# File 'lib/rocketio/controller/authorization.rb', line 51

def authorization_required?
  token_auth[requested_method] || token_auth[:*]
end

#backObject

Sugar for redirect (example: redirect back)



401
402
403
# File 'lib/rocketio/controller/helpers.rb', line 401

def back
  request.referer
end

#basic_authObject



53
# File 'lib/rocketio/controller/authentication.rb', line 53

def basic_auth; RocketIO::EMPTY_HASH end

#beforeObject



82
# File 'lib/rocketio/controller/filters.rb', line 82

def before; RocketIO::EMPTY_HASH end

#cache_control(*values) ⇒ Object

Specify response freshness policy for HTTP caches (Cache-Control header). Any number of non-value directives (:public, :private, :no_cache, :no_store, :must_revalidate, :proxy_revalidate) may be passed along with a Hash of value directives (:max_age, :min_stale, :s_max_age).

cache_control :public, :must_revalidate, :max_age => 60
=> Cache-Control: public, must-revalidate, max-age=60

See RFC 2616 / 14.9 for more on standard cache control directives: tools.ietf.org/html/rfc2616#section-14.9.1



290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/rocketio/controller/helpers.rb', line 290

def cache_control *values
  if values.last.kind_of?(Hash)
    hash = values.pop
    hash.reject! { |k,v| v == false }
    hash.reject! { |k,v| values << k if v == true }
  else
    hash = {}
  end

  values.map! { |value| value.to_s.tr('_','-') }
  hash.each do |key, value|
    key = key.to_s.tr('_', '-')
    value = value.to_i if key == "max-age"
    values << "#{key}=#{value}"
  end

  response[RocketIO::CACHE_CONTROL] = values.join(', ') if values.any?
end

#call(env) ⇒ Rack::Response

call requested method

Parameters:

  • env (Hash)

Returns:

  • (Rack::Response)


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/rocketio/controller.rb', line 29

def call env
  @__env__ = env
  catch :__response__ do

    api[requested_method] || error(501)

    if error_handlers[500]
      begin
        __call__(env)
      rescue Exception => e
        error(500, e)
      end
    else
      __call__(env)
    end
  end
end

#charset(charset) ⇒ Object

shorthand for content_type(charset: ‘something’)



195
196
197
# File 'lib/rocketio/controller/helpers.rb', line 195

def charset charset
  content_type(charset: charset)
end

#client_error?Boolean

whether or not the status is set to 4xx

Returns:

  • (Boolean)


53
54
55
# File 'lib/rocketio/controller/helpers.rb', line 53

def client_error?
  response.status.between? 400, 499
end

#content_type(*args) ⇒ Object

returns, set or update content type. if called without args it will return current content type. if called with a single argument, given argument will be set as content type. if a type and hash given it will set brand new content type composed of given type and opts. if only a hash given it will update current content type with given opts.

if no content type is set it will use default one + given opts.

Examples:

set content type

content_type '.json'

set content type with some params

content_type '.json', level: 1

add params to current content type

content_type comment: 'Boo!'


215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/rocketio/controller/helpers.rb', line 215

def content_type *args
  return response[RocketIO::CONTENT_TYPE] if args.empty?
  params = args.last.is_a?(Hash) ? args.pop.map {|kv| kv.map!(&:to_s)}.to_h : {}
  default = params.delete('default')

  if type = args.first
    mime_type = mime_type(type) || default || raise(ArgumentError, "Unknown media type: %p" % type)
  else
    mime_type = response[RocketIO::CONTENT_TYPE]
  end
  mime_type ||= RocketIO::DEFAULT_CONTENT_TYPE

  mime_type, _params = mime_type.split(';')
  if _params
    params = _params.split(',').map! {|o| o.strip.split('=')}.to_h.merge!(params)
  end

  if params.any?
    mime_type << '; '
    mime_type << params.map do |key, val|
      val = val.inspect if val =~ /[";,]/
      [key, val]*'='
    end.join(', ')
  end
  response[RocketIO::CONTENT_TYPE] = mime_type
end

#cookiesObject

shorthand for request.cookies, response.set_cookie and response.delete_cookie

Examples:

Setting a cookie

cookies['cookie-name'] = 'value'

Reading a cookie

cookies['cookie-name']

Setting a cookie with custom options

cookies['question_of_the_day'] = {
  value: 'who is not who?',
  expires: Date.today + 1,
  secure: true
}

Deleting a cookie

cookies.delete('cookie-name')


22
23
24
# File 'lib/rocketio/controller/cookies.rb', line 22

def cookies
  @__cookies__ ||= RocketIO::Cookies.new(request.cookies, response)
end

#digest_authObject



106
# File 'lib/rocketio/controller/authentication.rb', line 106

def digest_auth; RocketIO::EMPTY_HASH end

#engineObject



74
# File 'lib/rocketio/controller/render/engine.rb', line 74

def engine; RocketIO::DEFAULT_ENGINE end

#error(code, *args) ⇒ Object Also known as: error!

if there is a handler defined for given code it will be executed and the result used as body. otherwise the error behaves exactly as halt.

given args will be passed either to handler(if any defined) or to halt



56
57
58
59
# File 'lib/rocketio/controller/error_handlers.rb', line 56

def error code, *args
  error_handlers[code] || halt(code, *args)
  halt(code, __error__(code, *args))
end

#error_handlersObject



49
# File 'lib/rocketio/controller/error_handlers.rb', line 49

def error_handlers; RocketIO::EMPTY_HASH end

#etag(value, options = {}) ⇒ Object

Set the response entity tag (HTTP ‘ETag’ header) and halt if conditional GET matches. The value argument is an identifier that uniquely identifies the current version of the resource. The kind argument indicates whether the etag should be used as a :strong (default) or :weak cache validator.

When the current request includes an ‘If-None-Match’ header with a matching etag, execution is immediately halted. If the request method is GET or HEAD, a ‘304 Not Modified’ response is sent.



371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
# File 'lib/rocketio/controller/helpers.rb', line 371

def etag value, options = {}
  # Before touching this code, please double check RFC 2616 14.24 and 14.26.
  options      = {:kind => options} unless Hash === options
  kind         = options[:kind] || :strong
  new_resource = options.fetch(:new_resource) { request.post? }

  unless RocketIO::ETAG_KINDS.include?(kind)
    raise ArgumentError, ":strong or :weak expected"
  end

  value = '"%s"' % value
  value = "W/#{value}" if kind == :weak
  response[RocketIO::ETAG] = value

  if response.successful? || response.not_modified?
    if etag_matches?(env[RocketIO::HTTP_IF_NONE_MATCH], new_resource)
      response.status = request.safe? ? 304 : 412
      halt
    end

    if env[RocketIO::HTTP_IF_MATCH]
      unless etag_matches?(env[RocketIO::HTTP_IF_MATCH], new_resource)
        response.status = 412
        halt
      end
    end
  end
end

#expires(amount, *values) ⇒ Object

Set the Expires header and Cache-Control/max-age directive. Amount can be an integer number of seconds in the future or a Time object indicating when the response should be considered “stale”. The remaining “values” arguments are passed to the #cache_control helper:

expires 500, :public, :must_revalidate
=> Cache-Control: public, must-revalidate, max-age=60
=> Expires: Mon, 08 Jun 2009 08:50:17 GMT


318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/rocketio/controller/helpers.rb', line 318

def expires amount, *values
  values << {} unless values.last.kind_of?(Hash)

  if amount.is_a?(Integer)
    time    = Time.now + amount.to_i
    max_age = amount
  else
    time    = time_for amount
    max_age = time - Time.now
  end

  values.last.merge!(:max_age => max_age)
  cache_control(*values)

  response[RocketIO::EXPIRES] = time.httpdate
end

#flashObject

Examples:

flash[:alert] = 'some secret'
p flash[:alert] #=> "some secret"
p flash[:alert] #=> nil


150
151
152
# File 'lib/rocketio/controller/helpers.rb', line 150

def flash
  @__flash_proxy__ ||= RocketIO::Flash.new(session)
end

#halt(*args) ⇒ Object

stop executing any code and send response to browser.

accepts an arbitrary number of arguments. if first argument is a Rack::Response, halting right away using the first arg as response and ignore other args.

if first arg is a Array, updating current response using first array element as status, second to update headers and 3rd as body

if some arg is an Integer, it will be used as status code. if some arg is a Hash, it is treated as headers. any other args are treated as body.

if no args given it halts with current response.

Examples:

returning “Well Done” body with 200 status code

halt 'Well Done'

halting with current response without alter it in any way

halt

returning a error message with 500 code:

halt 500, 'Sorry, some fatal error occurred'

custom content type

halt File.read('/path/to/theme.css'), 'Content-Type' => mime_type('.css')

sending custom Rack response

halt [200, {'Content-Disposition' => "attachment; filename=some-file"}, some_IO_instance]

Parameters:

  • *args (Array)


121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/rocketio/controller/helpers.rb', line 121

def halt *args
  args.each do |a|
    case a
    when Rack::Response
      throw(:__response__, a.finish)
    when Fixnum
      response.status = a
    when Array
      if a.size == 3
        response.status = a[0]
        response.headers.update(a[1])
        response.body = a[2]
        break
      else
        response.body = a
      end
    when Hash
      response.headers.update(a)
    else
      response.body = a
    end
  end
  throw(:__response__, response.finish)
end

#headers(hash = nil) ⇒ Object

Set multiple response headers with Hash.



189
190
191
192
# File 'lib/rocketio/controller/helpers.rb', line 189

def headers hash = nil
  response.headers.merge!(hash) if hash
  response.headers
end

#http_1_1?Boolean

returns true for HTTP/1.1 requests

Returns:

  • (Boolean)


68
69
70
# File 'lib/rocketio/controller/helpers.rb', line 68

def http_1_1?
  env[RocketIO::HTTP_VERSION] == RocketIO::HTTP_1_1
end

#informational?Boolean

whether or not the status is set to 1xx

Returns:

  • (Boolean)


38
39
40
# File 'lib/rocketio/controller/helpers.rb', line 38

def informational?
  response.status.between? 100, 199
end

#invoke_after_filter(method = requested_method) ⇒ Object



109
110
111
112
# File 'lib/rocketio/controller/filters.rb', line 109

def invoke_after_filter method = requested_method
  __send__(after[:*]) if after[:*]
  __send__(after[method]) if after[method]
end

#invoke_around_filter(method = requested_method, block) ⇒ Object

passing blocks somehow tends to add some overhead so passing the proc as a common argument



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/rocketio/controller/filters.rb', line 93

def invoke_around_filter method = requested_method, block
  if around[:*]
    __send__ around[:*], proc {
      if around[method]
        __send__(around[method], block)
      else
        block.call
      end
    }
  elsif around[method]
    __send__(around[method], block)
  else
    block.call
  end
end

#invoke_before_filter(method = requested_method) ⇒ Object



86
87
88
89
# File 'lib/rocketio/controller/filters.rb', line 86

def invoke_before_filter method = requested_method
  __send__(before[:*]) if before[:*]
  __send__(before[method]) if before[method]
end

#last_modified(time) ⇒ Object

Set the last modified time of the resource (HTTP ‘Last-Modified’ header) and halt if conditional GET matches. The time argument is a Time, DateTime, or other object that responds to to_time.

When the current request includes an ‘If-Modified-Since’ header that is equal or later than the time specified, execution is immediately halted with a ‘304 Not Modified’ response.



342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/rocketio/controller/helpers.rb', line 342

def last_modified time
  return unless time
  time = time_for(time)
  response[RocketIO::LAST_MODIFIED] = time.httpdate
  return if env[RocketIO::HTTP_IF_NONE_MATCH]

  if response.ok? && env[RocketIO::HTTP_IF_MODIFIED_SINCE]
    # compare based on seconds since epoch
    since = Time.httpdate(env[RocketIO::HTTP_IF_MODIFIED_SINCE]).to_i
    halt(304) if since >= time.to_i
  end

  if (response.successful? || response.precondition_failed?) && env[RocketIO::HTTP_IF_UNMODIFIED_SINCE]
    # compare based on seconds since epoch
    since = Time.httpdate(env[RocketIO::HTTP_IF_UNMODIFIED_SINCE]).to_i
    halt(412) if since < time.to_i
  end
rescue ArgumentError
end

#layoutObject

by default no layout used, so this method returns nil. controllers that uses a layout will override this method.



25
# File 'lib/rocketio/controller/render/layout.rb', line 25

def layout; end

#layoutsObject



83
# File 'lib/rocketio/controller/render/layouts.rb', line 83

def layouts; RocketIO::EMPTY_HASH end

#middlewareObject



30
# File 'lib/rocketio/controller/middleware.rb', line 30

def middleware; RocketIO::EMPTY_ARRAY end

#not_found?Boolean

whether or not the status is set to 404

Returns:

  • (Boolean)


63
64
65
# File 'lib/rocketio/controller/helpers.rb', line 63

def not_found?
  response.status == 404
end

#pass(controller, *args) ⇒ Object

switch controller and halt with returned response. any arguments will be passed to requested method.

Examples:

pass control to User controller, call requested method without arguments

pass User

pass control to User controller, call requested method with [:bob, :bobsen] arguments

pass User, :bob, :bobsen


85
86
87
# File 'lib/rocketio/controller/helpers.rb', line 85

def pass controller, *args
  halt controller.new(requested_method, args).call(env)
end

#permanent_redirect(uri) ⇒ Object



164
165
166
167
168
# File 'lib/rocketio/controller/helpers.rb', line 164

def permanent_redirect uri
  response.status = 301
  response[RocketIO::LOCATION] = uri(uri.to_s)
  halt
end

#redirect(uri) ⇒ Object

Halt processing and redirect to the URI provided.



155
156
157
158
159
160
161
162
# File 'lib/rocketio/controller/helpers.rb', line 155

def redirect uri
  response.status = http_1_1? && !get? ? 303 : 302

  # According to RFC 2616 section 14.30, "the field value consists of a
  # single absolute URI"
  response[RocketIO::LOCATION] = uri(uri.to_s)
  halt
end

#redirect?Boolean

whether or not the status is set to 3xx

Returns:

  • (Boolean)


48
49
50
# File 'lib/rocketio/controller/helpers.rb', line 48

def redirect?
  response.status.between? 300, 399
end

#render(template = nil, opts = {}) ⇒ Object

if called without arguments render a template with lowercased name of current request method, e.g. get for GET, post for POST etc. at first it will look between defined templates. then it will search a file. it will try each extension the effective engine has registered, e.g. .erb, .rhtml for ERB. it will search in the folder the controller was defined in(NOT in path_to_templates, which is used for defined templates only). so put each controller in a separate folder to avoid templates clash.

if no file found a TemplateError will be raised. if a block given it will use the the string returned by the block as template and wont search for defined nor file templates.

by default ERB engine will be used (@see engine).

for layout it will take one given through options or one defined at class level. if none given, it will render without layout. to use a layout path_to_layouts should be defined at class level.

by default it will use current instance as scope. to render in a isolated scope, set it via :scope option

to pass some local variables use :locals option

Examples:

render ./get.erb without layout

class Pages < RocketIO::Controller

  def get
    render
  end
end

render ./get.erb with :master layout

class Pages < RocketIO::Controller
  layout :master

  def get
    render
  end
end

render ./get.erb with explicit :master layout

class Pages < RocketIO::Controller

  def get
    render(layout: :master)
  end
end

render within isolated scope

class Pages < RocketIO::Controller

  def get
    render(scope: Object.new)
  end
end

render with custom locals

class Pages < RocketIO::Controller

  def get
    render(locals: {x: 'y'})
  end
end


67
68
69
70
71
72
73
74
75
76
# File 'lib/rocketio/controller/render.rb', line 67

def render template = nil, opts = {}
  opts, template = template, nil if template.is_a?(::Hash)
  engine, engine_opts = resolve_engine(opts)
  template = block_given? ? yield : resolve_template(template, engine)
  scope    = opts.fetch(:scope, self)
  locals   = template_vars.merge(opts.fetch(:locals, RocketIO::EMPTY_HASH)).freeze
  layout   = opts.fetch(:layout, self.layout)
  template = compile_template(template, engine, engine_opts).render(scope, locals)
  layout   ? render_layout(layout, opts) {template} : template
end

#render_layout(template = nil, opts = {}, &block) ⇒ Object

render a template that yields the given block. that’s it, a layout is a template that yields given string.

layout can be specified two ways:

- as layout name
- as string

if both given a ArgumentError error raised. if :template option given, no layout lookups will occur.

otherwise… if no layout name given, it will use the one set at class level. if no layout set at class level and no layout given, it will raise a RuntimeError.

then it will search for given layout between defined ones. if none found, it will search a file in path_to_layouts folder. it will try each extension registered with effective engine. if no file found it will raise a TemplateError.

block is required and should return the string to be yielded.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/rocketio/controller/render.rb', line 99

def render_layout template = nil, opts = {}, &block
  template && opts[:template] && raise(ArgumentError, 'Both layout name and :template option given. Please use either one.')

  opts, template = template, nil if template.is_a?(::Hash)
  engine, engine_opts = resolve_engine(opts)
  template = if template
    resolve_layout(template, engine)
  else
    opts[:template] || begin
      self.layout || raise(RocketIO::LayoutError, 'No default layout set and no explicit layout given')
      resolve_layout(self.layout, engine)
    end
  end

  scope  = opts.fetch(:scope, self)
  locals = template_vars.merge(opts.fetch(:locals, RocketIO::EMPTY_HASH)).freeze
  compile_template(template, engine, engine_opts)
    .render(scope, locals, &(block || RocketIO::EMPTY_STRING_PROC))
end

#request_token_auth(realm = RocketIO::DEFAULT_TOKEN_AUTH_REALM) ⇒ Object



47
48
49
# File 'lib/rocketio/controller/authorization.rb', line 47

def request_token_auth realm = RocketIO::DEFAULT_TOKEN_AUTH_REALM
  RocketIO::TokenAuth.authentication_request(realm)
end

#send_file(path, opts = {}) ⇒ Object

Use the contents of the file at path as the response body.



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/rocketio/controller/helpers.rb', line 254

def send_file path, opts = {}
  if opts[:type] or not response[RocketIO::CONTENT_TYPE]
    content_type(opts[:type] || File.extname(path), default: RocketIO::APPLICATION_OCTET_STREAM)
  end

  disposition = opts[:disposition]
  filename    = opts[:filename]
  disposition = 'attachment' if disposition.nil? and filename
  filename    = path         if filename.nil?
  attachment(filename, disposition) if disposition

  last_modified(opts[:last_modified]) if opts[:last_modified]

  file      = Rack::File.new(nil)
  file.path = path
  result    = file.serving(env)
  result[1].each { |k,v| headers[k] ||= v }
  headers[RocketIO::CONTENT_LENGTH] = result[1][RocketIO::CONTENT_LENGTH]
  opts[:status] &&= Integer(opts[:status])
  response.status = opts[:status] || result[0]
  response.body = result[2]
  halt
rescue Errno::ENOENT
  error(404)
end

#server_error?Boolean

whether or not the status is set to 5xx

Returns:

  • (Boolean)


58
59
60
# File 'lib/rocketio/controller/helpers.rb', line 58

def server_error?
  response.status.between? 500, 599
end

#sessionsObject



62
# File 'lib/rocketio/controller/sessions.rb', line 62

def sessions; end

#success?Boolean

whether or not the status is set to 2xx

Returns:

  • (Boolean)


43
44
45
# File 'lib/rocketio/controller/helpers.rb', line 43

def success?
  response.status.between? 200, 299
end

#template_varsObject



30
31
32
# File 'lib/rocketio/controller/render/template_vars.rb', line 30

def template_vars
  __template_vars__.each_with_object({}) {|(k,v),o| o[k] = __send__(v)}
end

#templatesObject



81
# File 'lib/rocketio/controller/render/templates.rb', line 81

def templates; RocketIO::EMPTY_HASH end

#time_for(value) ⇒ Object

Generates a Time object from the given value. Used by #expires and #last_modified.



407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/rocketio/controller/helpers.rb', line 407

def time_for value
  if value.respond_to?(:to_time)
    value.to_time
  elsif value.is_a?(Time)
    value
  elsif value.respond_to?(:new_offset)
    # DateTime#to_time does the same on 1.9
    d = value.new_offset 0
    t = Time.utc(d.year, d.mon, d.mday, d.hour, d.min, d.sec + d.sec_fraction)
    t.getlocal
  elsif value.respond_to?(:mday)
    # Date#to_time does the same on 1.9
    Time.local(value.year, value.mon, value.mday)
  elsif value.is_a? Numeric
    Time.at value
  else
    Time.parse value.to_s
  end
rescue ArgumentError => boom
  raise boom
rescue Exception
  raise ArgumentError, "unable to convert #{value.inspect} to a Time object"
end

#token_authObject



31
# File 'lib/rocketio/controller/authorization.rb', line 31

def token_auth; RocketIO::EMPTY_HASH end

#uri(addr = nil, absolute = true, add_script_name = true) ⇒ Object

Generates the absolute URI for a given path in the app. Takes Rack routers and reverse proxies into account.



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/rocketio/controller/helpers.rb', line 172

def uri addr = nil, absolute = true, add_script_name = true
  return addr if addr && addr =~ /\A[A-z][A-z0-9\+\.\-]*:/
  uri = [host = ""]
  if absolute
    host << "http#{'s' if request.secure?}://"
    if request.forwarded? or request.port != (request.secure? ? 443 : 80)
      host << request.host_with_port
    else
      host << request.host
    end
  end
  uri << request.script_name.to_s if add_script_name
  uri << (addr ? addr : request.path_info).to_s
  File.join(uri)
end

#user?Boolean

Returns:

  • (Boolean)


108
# File 'lib/rocketio/controller/authentication.rb', line 108

def user?; env[RocketIO::REMOTE_USER] end

#validate_or_request_authentication_if_neededObject

checks whether authentication is required and send an authorization request if credentials not present or invalid



112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/rocketio/controller/authentication.rb', line 112

def validate_or_request_authentication_if_needed
  return unless auth = authentication_required?
  return unless prompt = auth[:class].new(proc {}, *auth[:arguments]) do |*a|
    self.__send__(auth[:method], *a)
  end.call(
    if RocketIO::HTTP_AUTHORIZATION_KEYS.detect {|key| env.has_key?(key)}
      env
    else
      env.merge(RocketIO::HTTP_AUTHORIZATION_KEYS.first => auth[:mock] % env[RocketIO::PATH_INFO])
    end
  )
  throw(:__response__, prompt)
end

#validate_or_request_authorization_if_neededObject



33
34
35
36
37
# File 'lib/rocketio/controller/authorization.rb', line 33

def validate_or_request_authorization_if_needed
  return unless auth = authorization_required?
  return if validate_token_auth(&auth[:block])
  throw(:__response__, request_token_auth(auth[:realm]))
end

#validate_or_request_token_auth(realm = RocketIO::DEFAULT_TOKEN_AUTH_REALM, &block) ⇒ Object



39
40
41
# File 'lib/rocketio/controller/authorization.rb', line 39

def validate_or_request_token_auth realm = RocketIO::DEFAULT_TOKEN_AUTH_REALM, &block
  validate_token_auth(&block) || request_token_auth(realm)
end

#validate_token_auth(&block) ⇒ Object



43
44
45
# File 'lib/rocketio/controller/authorization.rb', line 43

def validate_token_auth &block
  RocketIO::TokenAuth.authenticate(env, &block)
end

#websocket?Boolean

Returns:

  • (Boolean)


4
5
6
7
# File 'lib/rocketio/controller/websocket.rb', line 4

def websocket?
  @__is_websocket__ ||= websocket_connection? && websocket_upgrade? ? 1 : 0
  @__is_websocket__ == 1
end

#websocket_connection?Boolean

Returns:

  • (Boolean)


9
10
11
# File 'lib/rocketio/controller/websocket.rb', line 9

def websocket_connection?
  env[RocketIO::HTTP_CONNECTION].to_s.downcase.split(/ *, */).include?(RocketIO::UPGRADE)
end

#websocket_responseObject



17
18
19
# File 'lib/rocketio/controller/websocket.rb', line 17

def websocket_response
  [-1, {}, []]
end

#websocket_upgrade?Boolean

Returns:

  • (Boolean)


13
14
15
# File 'lib/rocketio/controller/websocket.rb', line 13

def websocket_upgrade?
  env[RocketIO::HTTP_UPGRADE].to_s.downcase == RocketIO::WEBSOCKET
end

#xhr?Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/rocketio/controller/helpers.rb', line 72

def xhr?
  env[RocketIO::HTTP_X_REQUESTED_WITH] == RocketIO::XML_HTTP_REQUEST
end