Class: E

Inherits:
Object
  • Object
show all
Includes:
Rack::Utils
Defined in:
lib/e-core/e-core.rb,
lib/e-more/view/base.rb,
lib/e-more/view/setup.rb,
lib/e-core/instance/base.rb,
lib/e-core/instance/halt.rb,
lib/e-core/instance/invoke.rb,
lib/e-core/instance/stream.rb,
lib/e-core/instance/cookies.rb,
lib/e-core/instance/helpers.rb,
lib/e-core/instance/session.rb,
lib/e-core/instance/redirect.rb,
lib/e-core/instance/send_file.rb,
lib/e-core/instance/setup/auth.rb,
lib/e-core/instance/setup/generic.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#action_setupObject

Returns the value of attribute action_setup.



3
4
5
# File 'lib/e-core/instance/base.rb', line 3

def action_setup
  @action_setup
end

Class Method Details

.[](action_or_action_with_format) ⇒ Object

Examples:

class Forum < E
  format '.html', '.xml'

  def posts
  end
end

App[:posts]             #=> /forum/posts
App['posts.html']       #=> /forum/posts.html
App['posts.xml']        #=> /forum/posts.xml
App['posts.json']       #=> nil


47
48
49
50
51
# File 'lib/e-core/controller/setups_reader.rb', line 47

def [] action_or_action_with_format
  mounted? || raise("`[]' method works only on mounted controllers")
  @__e__route_by_action[action_or_action_with_format] ||
    @__e__route_by_action_with_format[action_or_action_with_format]
end

.accept_automount?Boolean

Returns:

  • (Boolean)


42
43
44
# File 'lib/e-core/controller/mounter.rb', line 42

def accept_automount?
  true unless @reject_automount
end

.action_setupObject



6
# File 'lib/e-core/controller/setups_reader.rb', line 6

def action_setup;  @__e__action_setup end

.after(*matchers, &proc) ⇒ Object



242
243
244
# File 'lib/e-core/controller/setups_writer.rb', line 242

def after *matchers, &proc
  add_setup :z, *matchers, &proc
end

.alias_action(url, action) ⇒ Object

Note:

private and protected methods usually are not publicly available via HTTP. however, if you add an action alias to such a method, it becomes public via its alias. to alias a private/protected method and keep it private, use standard ruby ‘alias` or `alias_method` rather than `alias_action`

allow to set routes directly, without relying on path rules.

Examples:

make :bar method to serve /bar, /some/url and /some/another/url

def bar
  # ...
end

alias_action 'some/url', :bar
alias_action 'some/another/url', :bar

Parameters:

  • url (String)

    target URL

  • action (Symbol)


68
69
70
71
# File 'lib/e-core/controller/setups_writer.rb', line 68

def alias_action url, action
  return if mounted?
  ((@__e__alias_actions ||= {})[action]||=[]) << url
end

.alias_actionsObject



60
61
62
# File 'lib/e-core/controller/setups_reader.rb', line 60

def alias_actions
  @__e__alias_actions || {}
end

.alias_after(action, *others) ⇒ Object



247
248
249
250
# File 'lib/e-core/controller/setups_writer.rb', line 247

def alias_after action, *others
  return if mounted?
  (@__e__after_aliases ||= {})[action] = others
end

.alias_before(action, *others) ⇒ Object

allow to run multiple callbacks for same action. action will run its callback(s)(if any) regardless aliased callbacks. callbacks will run in the order was added, that’s it, if an aliased callback defined before action’s callback, it will run first.

Examples:

run :save callback on :post_crud action

class App < E
  before :save do
    # ...
  end

  def post_crud
    # ...
  end
  alias_before :post_crud, :save
end

Parameters:

  • action (Symbol)
  • others (Array)

    callbacks to run before given actions, beside its own callback



236
237
238
239
# File 'lib/e-core/controller/setups_writer.rb', line 236

def alias_before action, *others
  return if mounted?
  (@__e__before_aliases ||= {})[action] = others
end

.appObject



3
# File 'lib/e-core/controller/setups_reader.rb', line 3

def app;           @__e__app    end

.around(*matchers, &proc) ⇒ Object

use ‘around` when you need some action to run inside given block. call `invoke_action` where you need action to be executed.

Examples:

graciously throw an error if some /remote/ action takes more than 5 seconds to run

class App < E

  around /remote/ do

    Timeout.timeout(5) do
      begin
        invoke_action # executing action
      rescue => e
        fail 500, e.message
      end
    end

  end

  def remote_init
    # occasionally slow action
  end

  def remote_post
    # occasionally slow action
  end

  def remote_fetch
    # occasionally slow action
  end
end


283
284
285
# File 'lib/e-core/controller/setups_writer.rb', line 283

def around *matchers, &proc
  add_setup :around, *matchers, &proc
end

.base_urlObject Also known as: baseurl



21
22
23
# File 'lib/e-core/controller/setups_reader.rb', line 21

def base_url
  @__e__base_url || default_route
end

.before(*matchers, &proc) ⇒ Object Also known as: setup, on

Note:

setups will be executed in the order they was added

Note:

#before, #setup and #on are aliases

add setups to be executed before/after given(or all) actions.

before :blue, /red/ do
  # ...
end

Examples:

setup to be executed before any action

setup do
  # ...
end

defining the setup to be executed only before :index

before :index do
   # ...
end

defining a setup to be executed after :post_login and :put_edit actions

after :post_login, :put_edit do
  # ...
end

running a setup before :blue action

as well as before actions matching "red"

running a setup for any action on .json format

on '.json' do
  # ...
end

running a setup for :api action on .json format

on 'api.json' do
  # ...
end


205
206
207
# File 'lib/e-core/controller/setups_writer.rb', line 205

def before *matchers, &proc
  add_setup :a, *matchers, &proc
end

.call(env) ⇒ Object



7
8
9
# File 'lib/e-core/controller/mounter.rb', line 7

def call env
  mount.call(env)
end

.canonicalsObject



26
27
28
# File 'lib/e-core/controller/setups_reader.rb', line 26

def canonicals
  @__e__canonicals || []
end

.default_routeObject



30
31
32
# File 'lib/e-core/controller/setups_reader.rb', line 30

def default_route
  @__e__default_route ||= EUtils.class_to_route(self.name).freeze
end

.define_setup_method(meth) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/e-core/e-core.rb', line 47

def define_setup_method meth
  (class << self; self end).class_exec do
    define_method meth do |*args, &proc|
      add_setup(:a) { self.send meth, *args, &proc }
    end
  end
end

.disable_format_for(*matchers) ⇒ Object

allow to disable format for specific action(s). any number of arguments accepted(zero arguments will have no effect).

format '.xml'
disable_format_for :read

Examples:

all actions will serve .xml format,

except :read action, which wont serve any format

actions matching /api/ wont serve any formats


disable_format_for /api/


164
165
166
167
# File 'lib/e-core/controller/setups_writer.rb', line 164

def disable_format_for *matchers
  return if mounted?
  (@__e__disable_formats_for ||= []).concat matchers
end

.error(*error_codes, &proc) ⇒ Object

define a block to be executed on errors. the block should return a [String] error message.

multiple error codes accepted. if no error codes given, the block will be effective for any error type.

Examples:

handle 404 errors:

class App < E

  error 404 do |error_message|
    "Some weird error occurred: #{ error_message }"
  end
end

Parameters:

  • code (Integer)
  • proc (Proc)


311
312
313
314
315
316
317
# File 'lib/e-core/controller/setups_writer.rb', line 311

def error *error_codes, &proc
  return if mounted?
  proc || raise(ArgumentError, 'Error handlers require a block')
  error_codes.any? || error_codes = [:*]
  meth = proc_to_method(:error_handlers, *error_codes, &proc)
  error_codes.each {|c| (@__e__error_handlers ||= {})[c] = [meth, proc.arity]}
end

.error_handler(error_code) ⇒ Object



68
69
70
# File 'lib/e-core/controller/setups_reader.rb', line 68

def error_handler error_code
  ((@__e__error_handlers || {}).find {|k,v| error_code == k} || []).last
end

.external_setup!(&setup) ⇒ Object



73
74
75
76
77
# File 'lib/e-core/controller/mounter.rb', line 73

def external_setup! &setup
  @__e__setup_container = :external
  self.class_exec &setup
  @__e__setup_container = nil
end

.format(*formats) ⇒ Object

automatically setting URL extension and Content-Type. this method will set formats for all actions.

Examples:


class App < E

  format '.html', '.xml', '.etc'

end


103
104
105
106
# File 'lib/e-core/controller/setups_writer.rb', line 103

def format *formats
  return if mounted?
  (@__e__formats ||= []).concat formats
end

.format_for(matcher, *formats) ⇒ Object

setting format(s) for specific action. first argument is the action name or a Regex matching multiple action names. consequent arguments are the formats to be served.

class App < E

  format_for :api, '.json', '.xml'
  format '.html'

end

Examples:

make :page action to serve .html format


class App < E

  format_for :page, '.html'

end

make :page action to serve .html and .xml formats


class App < E

  format_for :page, '.html', '.xml'

end

make actions that match /api/ to serve .json format


class App < E

  format_for /api/, '.json'

end

make :api action to serve .json and .xml formats

and any other actions to serve .html format


146
147
148
149
# File 'lib/e-core/controller/setups_writer.rb', line 146

def format_for matcher, *formats
  return if mounted?
  (@__e__formats_for ||= []) << [matcher, formats]
end

.formats(action) ⇒ Object



64
65
66
# File 'lib/e-core/controller/setups_reader.rb', line 64

def formats action
  (@__e__expanded_formats || {})[action] || []
end

.global_setup!(&setup) ⇒ Object



67
68
69
70
71
# File 'lib/e-core/controller/mounter.rb', line 67

def global_setup! &setup
  @__e__setup_container = :global
  self.class_exec self, &setup
  @__e__setup_container = nil
end

.hostsObject



5
# File 'lib/e-core/controller/setups_reader.rb', line 5

def hosts;         @__e__hosts || {}  end

.import(mdl) ⇒ Object

‘import` are used to share actions between controllers



42
43
44
45
# File 'lib/e-core/e-core.rb', line 42

def import mdl
  native_include(mdl)
  (@__e__imported_methods ||= []).concat mdl.public_instance_methods(false)
end

.inherited(ctrl) ⇒ Object

Note:

it wont accept any arguments

allow controllers to define ‘initialize` method that will run on clean state, before any Espresso stuff.



23
24
25
26
27
28
29
30
# File 'lib/e-core/e-core.rb', line 23

def inherited ctrl
  def ctrl.new *args
    o = allocate
    o.send :initialize # `initialize` is a private method, using `send`
    o.initialize_controller *args
    o
  end
end

.map(*args) ⇒ Object

setting controller’s base URL

if multiple paths provided, first path is treated as root, and other ones are treated as canonical routes. canonical routes allow controller to serve multiple roots.

also it accepts a Hash of options. if :host option given, controller will respond only to requests originating on given host. multiple hosts can be provided as an Array via :hosts option.

Examples:

respond only to requests from site.com

map host: 'site.com'

respond only to requests from site.com and site.net

map hosts: ['site.com', 'site.net']


19
20
21
22
# File 'lib/e-core/controller/setups_writer.rb', line 19

def map *args
  return if mounted?
  map! *args
end

.mapped?Boolean

Returns:

  • (Boolean)


8
# File 'lib/e-core/controller/setups_reader.rb', line 8

def mapped?;       @__e__base_url end

.middlewareObject



87
88
89
# File 'lib/e-core/controller/setups_reader.rb', line 87

def middleware
  @__e__middleware || []
end

.mount(*roots, &setup) ⇒ Object

used when mounted manually

Parameters:

  • roots (Array)

    first arg treated as base URL, consequent ones treated as canonical URLs.

  • setup (Proc)

    setup block. to be executed at class level



17
18
19
# File 'lib/e-core/controller/mounter.rb', line 17

def mount *roots, &setup
  @__e__app ||= EBuilder.new.mount(self, *roots, &setup).to_app
end

.mount!(app) ⇒ Object

used when mounted from an E instance

Parameters:

  • app (Object)

    EBuilder instance



25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/e-core/controller/mounter.rb', line 25

def mount! app
  return if mounted?
  @__e__app = app

  # Important - expand_formats! should run before expand_setups!
  expand_formats!
  expand_setups!
  generate_routes!
  lock!

  @__e__mounted = true
end

.mount_controllers(*controllers) ⇒ Object Also known as: mount_controller

Note:

sub-controllers wont be automounted when app built. though you can still can mount them manually.

Note:

any controller can be mounted only once, so do not try to mount same sub-controller into multiple controllers!

allow to mount sub-controllers under the base URL of parent controller. almost same as ‘import`, except actions will be executed in the sub-controller context.



82
83
84
85
86
87
88
89
# File 'lib/e-core/controller/setups_writer.rb', line 82

def mount_controllers *controllers
  (@__e__subcontrollers ||= [])
  controllers.each do |c|
    EUtils.is_app?(c) ?
      (c.reject_automount!; (@__e__subcontrollers << c).uniq!) :
      warn('"%s" should be a Espresso controller, skipping mount' % CGI.escape_html(c))
  end
end

.mounted?Boolean

Returns:

  • (Boolean)


9
# File 'lib/e-core/controller/setups_reader.rb', line 9

def mounted?;      @__e__mounted || @__e__app end

.new(*args, &proc) ⇒ Object

allow to create new applications by ‘E.new`

Examples:

app = E.new do
  # some setup...
end
require './controllers'
app.mount Something
app.run


16
17
18
# File 'lib/e-core/e-core.rb', line 16

def new *args, &proc
  EBuilder.new *args, &proc
end

.path_rule(from, to) ⇒ Object

Note:

default rules

  • “__” (2 underscores) => “-” (dash)

  • _” (3 underscores) => “/” (slash)

  • __” (4 underscores) => “.” (period)

add/update a path rule

Examples:

path_rule  "!" => ".html"

def some_action!
  # will resolve to some_action.html
end
path_rule  /_j$/ => ".json"

def some_action_j
  # will resolve to some_action.json
end


45
46
47
48
49
# File 'lib/e-core/controller/setups_writer.rb', line 45

def path_rule from, to
  return if mounted?
  from = %r[#{from}] unless from.is_a?(Regexp)
  (@__e__path_rules ||= Hash[EConstants::PATH_RULES]).update from => to
end

.path_rulesObject



53
54
55
56
57
58
# File 'lib/e-core/controller/setups_reader.rb', line 53

def path_rules
  @__e__sorted_path_rules ||= begin
    rules = @__e__path_rules || EConstants::PATH_RULES
    Hash[rules.sort {|a,b| b.first.source.size <=> a.first.source.size}].freeze
  end
end

.public_actionsArray

methods to be translated into HTTP paths. if controller has no methods, defining #index with some placeholder text.

HTTP path params passed to action as arguments. if arguments does not meet requirements, HTTP 404 error returned.

Examples:

class News < E
  map '/news'

  def index
    # ...
  end
  # will serve GET /news/index and GET /news

  def post_index
    # ...
  end
  # will serve POST /news/index and POST /news
end
class Forum < E
  map '/forum'

  def online_users
    # ...
  end
  # will serve GET /forum/online_users

  def post_create_user
    # ...
  end
  # will serve POST /forum/create_user
end
def foo arg1, arg2
end
# /foo/some-arg/some-another-arg        - OK
# /foo/some-arg                         - 404 error

def foo arg, *args
end
# /foo/at-least-one-arg                 - OK
# /foo/one/or/any/number/of/args        - OK
# /foo                                  - 404 error

def foo arg1, arg2 = nil
end
# /foo/some-arg/                        - OK
# /foo/some-arg/some-another-arg        - OK
# /foo/some-arg/some/another-arg        - 404 error
# /foo                                  - 404 error

def foo arg, *args, last
end
# /foo/at-least/two-args                - OK
# /foo/two/or/more/args                 - OK
# /foo/only-one-arg                     - 404 error

def foo *args
end
# /foo                                  - OK
# /foo/any/number/of/args               - OK

def foo *args, arg
end
# /foo/at-least-one-arg                 - OK
# /foo/one/or/more/args                 - OK
# /foo                                  - 404 error

Returns:

  • (Array)


76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/e-core/controller/actions.rb', line 76

def public_actions
  @__e__public_actions ||= begin

    actions = begin
      (self.public_instance_methods(false)) +
      (@__e__alias_actions    || {}).keys   +
      (@__e__imported_methods || [])
    end.uniq - (@__e__included_methods || [])
    
    if actions.empty?
      define_method :index do |*|
        'Get rid of this placeholder by defining %s#index' % self.class
      end
      actions << :index
    end
    actions
  end
end

.reject_automount!Object

use this when you do not want some controller(s) to be automounted



39
40
41
# File 'lib/e-core/controller/mounter.rb', line 39

def reject_automount!
  @reject_automount = true
end

.remap!(root, opts = {}) ⇒ Object

Note:

Important: all actions should be defined before re-mapping occurring

remap served root(s) by prepend given path to controller’s root.

Examples:

class Forum < E
  map '/forum', '/forums'
  # ...
end

app = E.new.mount(Forum, '/new-root')
# app will serve:
#   - /new-root/forum
#   - /new-root/forums


61
62
63
64
65
# File 'lib/e-core/controller/mounter.rb', line 61

def remap! root, opts = {}
  return if mounted?
  new_canonicals = canonicals.map {|c| EUtils.rootify_url(root, c)}
  map! EUtils.rootify_url(root, base_url), *new_canonicals.uniq, opts
end

.rewrite(rule, &proc) ⇒ Object Also known as: rewrite_rule



319
320
321
322
# File 'lib/e-core/controller/setups_writer.rb', line 319

def rewrite rule, &proc
  proc || raise(ArgumentError, "Rewrite rules requires a block to run")
  (@__e__rewrite_rules ||= []) << [rule, proc]
end

.rewrite_rulesObject



7
# File 'lib/e-core/controller/setups_reader.rb', line 7

def rewrite_rules; @__e__rewrite_rules || []  end

.route(*args) ⇒ String

build URL from given action name(or path) and consequent params

Returns:

  • (String)


14
15
16
17
18
19
# File 'lib/e-core/controller/setups_reader.rb', line 14

def route *args
  mounted? || raise("`route' works only on mounted controllers. Please consider to use `base_url' instead.")
  return base_url if args.size == 0
  (route = self[args.first]) && args.shift
  EUtils.build_path(route || base_url, *args)
end

.routesObject



4
# File 'lib/e-core/controller/setups_reader.rb', line 4

def routes;        @__e__routes end

.run(*args) ⇒ Object



3
4
5
# File 'lib/e-core/controller/mounter.rb', line 3

def run *args
  mount.run *args
end

.setup_aliases(position, action) ⇒ Object



72
73
74
75
76
77
78
79
80
# File 'lib/e-core/controller/setups_reader.rb', line 72

def setup_aliases position, action
  if position == :a
    (@__e__before_aliases || {})[action] || []
  elsif position == :z
    (@__e__after_aliases  || {})[action] || []
  else
    []
  end
end

.setups(position, action, format) ⇒ Object



82
83
84
85
# File 'lib/e-core/controller/setups_reader.rb', line 82

def setups position, action, format
  return [] unless (s = @__e__expanded_setups) && (s = s[position]) && (s = s[action])
  s[format] || []
end

.subcontrollersObject



91
92
93
# File 'lib/e-core/controller/setups_reader.rb', line 91

def subcontrollers
  (@__e__subcontrollers || []).uniq
end

.use(ware, *args, &proc) ⇒ Object

add Rack middleware to chain



288
289
290
291
292
# File 'lib/e-core/controller/setups_writer.rb', line 288

def use ware, *args, &proc
  return if mounted?
  (@__e__middleware ||= []).none? {|w| w.first == ware} && 
    @__e__middleware << [ware, args, proc]
end

Instance Method Details

#[](action) ⇒ Object



183
184
185
# File 'lib/e-core/instance/base.rb', line 183

def [] action
  self.class[action]
end

#actionObject



27
28
29
# File 'lib/e-core/instance/base.rb', line 27

def action
  action_setup && action_setup[:action]
end

#action_nameObject



45
46
47
# File 'lib/e-core/instance/base.rb', line 45

def action_name
  action_setup[:action_name]
end

#action_paramsObject

Examples:

def index id, status
  action_params
end
# GET /100/active
# => {:id => '100', :status => 'active'}


140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/e-core/instance/base.rb', line 140

def action_params
  return @__e__action_params if @__e__action_params

  action_params, given_params = {}, Array.new(action_params__array) # faster than dup
  action_setup[:action_arguments].each_with_index do |type_name, index|
    type, name = type_name
    if type == :rest
      action_params[name] = []
      until given_params.size < (action_setup[:action_arguments].size - index)
        action_params[name] << given_params.shift
      end
    else
      action_params[name] = given_params.shift
    end
  end
  @__e__action_params = EUtils.indifferent_params(action_params).freeze
end

#action_params__arrayObject



127
128
129
130
131
# File 'lib/e-core/instance/base.rb', line 127

def action_params__array
  @__e__action_params__array ||=
    (env[EConstants::ENV__ESPRESSO_PATH_INFO] || 
      env[EConstants::ENV__PATH_INFO]).to_s.split('/').reject(&:empty?).freeze
end

#action_with_formatObject



54
55
56
# File 'lib/e-core/instance/base.rb', line 54

def action_with_format
  @__e__action_with_format ||= (format ? action.to_s + format : action).freeze
end

#alias_actionsObject



191
192
193
# File 'lib/e-core/instance/base.rb', line 191

def alias_actions
  self.class.alias_actions[action] || []
end

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

same as ‘send_file` except it instruct browser to display save dialog



41
42
43
# File 'lib/e-core/instance/send_file.rb', line 41

def attachment path, opts = {}
  halt send_file path, opts.merge(:attachment => true)
end

#baseurlObject



173
# File 'lib/e-core/instance/base.rb', line 173

alias baseurl base_url

#basic_auth(opts = {}, &proc) ⇒ Object Also known as: auth

Examples:

protecting all actions via Basic authorization

auth { |user, pass| ['user', 'pass'] == [user, pass] }

protecting only :edit action

setup :edit do
  auth { |user, pass| ['user', 'pass'] == [user, pass] }
end

protecting only :edit and :delete actions

setup :edit, :delete do
  auth { |user, pass| ['user', 'pass'] == [user, pass] }
end

Parameters:

  • proc (Proc)
  • opts (Hash) (defaults to: {})

    a customizable set of options

Options Hash (opts):

  • :realm (String)

    default - AccessRestricted



21
22
23
# File 'lib/e-core/instance/setup/auth.rb', line 21

def basic_auth opts = {}, &proc
  __e__authorize! Rack::Auth::Basic, opts[:realm] || 'AccessRestricted', &proc
end

#call(env) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/e-core/instance/base.rb', line 62

def call env
  
  @__e__env     = env
  @__e__request = ERequest.new(env)
  @__e__format  = env[EConstants::ENV__ESPRESSO_FORMAT]

  e_response = catch :__e__catch__response__ do
    
    setup_action! unless action_setup

    min, max = action_setup[:required_arguments]
    given = action_params__array.size

    min && given < min &&
      styled_halt(EConstants::STATUS__NOT_FOUND, 'min params accepted: %s; params given: %s' % [min, given])

    max && given > max &&
      styled_halt(EConstants::STATUS__NOT_FOUND, 'max params accepted: %s; params given: %s' % [max, given])

    call!
  end
  e_response.body = [] if request.head?
  e_response.finish
end

#call_setups!(position = :a) ⇒ Object



123
124
125
# File 'lib/e-core/instance/base.rb', line 123

def call_setups! position = :a
  setups(position).each {|m| self.send m}
end

#canonicalObject Also known as: canonical?



49
50
51
# File 'lib/e-core/instance/base.rb', line 49

def canonical
  action_setup[:canonical]
end

#charset(charset) ⇒ Object



41
42
43
# File 'lib/e-core/instance/setup/generic.rb', line 41

def charset charset
  content_type :charset => charset
end

#chunked_stream(keep_open = true, &proc) ⇒ Object Also known as: chunk_stream



7
8
9
10
# File 'lib/e-core/instance/stream.rb', line 7

def chunked_stream keep_open = true, &proc
  transfer_encoding 'chunked'
  streamer EStream::Chunked, keep_open, &proc
end

#content_type(*args) ⇒ Object

set/get or update Content-Type header.

if no args given, actual Content-Type returned.

To set charset alongside Content-Type, use :charset option.

Examples:

all actions matching /api/ will return JSON Content-Type

class App < E

  setup /api/ do
    content_type '.json'
  end

  # ...
end

Parameters:

  • args (Array)


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/e-core/instance/setup/generic.rb', line 20

def content_type *args
  return response[EConstants::HEADER__CONTENT_TYPE] if args.empty?
  type, opts = nil, {}
  args.each {|a| a.is_a?(Hash) ? opts.update(a) : type = a}
  if type
    type = mime_type(type, type)
  else
    if actual = response[EConstants::HEADER__CONTENT_TYPE]
      type, charset = actual.split(';')
      opts[:charset] ||= charset
    else
      type = EConstants::CONTENT_TYPE__DEFAULT
    end
  end
  if charset = opts[:charset]
    type = '%s; charset=%s' % [type, charset]
  end
  response[EConstants::HEADER__CONTENT_TYPE] = type
end

#cookiesObject

shorthand for ‘response.set_cookie` and `response.delete_cookie`.

cookies = ‘value’

cookies #=> value

cookies = => ‘who is not who?’, :expires => Date.today + 1, :secure => true

cookies.delete ‘cookie-name’

Examples:

Setting a cookie

Reading a cookie

Setting a cookie with custom options

Deleting a cookie



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/e-core/instance/cookies.rb', line 18

def cookies
  @__e__cookies_proxy ||= Class.new do

    def initialize controller
      @controller, @request, @response =
        controller, controller.request, controller.response
    end

    # set cookie header
    #
    # @param [String, Symbol] key
    # @param [String, Hash] val
    # @return [Boolean]
    def []= key, val
      @response.set_cookie key, val
    end

    # get cookie by key
    def [] key
      @request.cookies[key]
    end

    # instruct browser to delete a cookie
    #
    # @param [String, Symbol] key
    # @param [Hash] opts
    # @return [Boolean]
    def delete key, opts ={}
      @response.delete_cookie key, opts
    end

    def method_missing *args
      @request.cookies.send *args
    end
  end.new self
end

#delayed_redirect(*args) ⇒ Object Also known as: deferred_redirect

ensure the browser will be redirected after code execution finished



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/e-core/instance/redirect.rb', line 25

def delayed_redirect *args
  status = args.first.is_a?(Numeric) ? args.shift : EConstants::STATUS__REDIRECT
  app = EUtils.is_app?(args.first) ? args.shift : nil
  action = args.first.is_a?(Symbol) ? args.shift : nil
  if app && action
    target = app.route action, *args
  elsif app
    target = app.route *args
  elsif action
    target = route action, *args
  else
    target = EUtils.build_path *args
  end
  response.body = []
  response.redirect target, status
end

#digest_auth(opts = {}, &proc) ⇒ Object

Examples:

digest auth - 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

digest auth - plain password

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

Parameters:

  • proc (Proc)
  • opts (Hash) (defaults to: {})

    a customizable set of options

Options Hash (opts):

  • :realm (String)

    default - AccessRestricted

  • :opaque (String)

    default - same as realm

  • :passwords_hashed (Boolean)

    default - false



53
54
55
56
57
# File 'lib/e-core/instance/setup/auth.rb', line 53

def digest_auth opts = {}, &proc
  opts[:realm]  ||= 'AccessRestricted'
  opts[:opaque] ||= opts[:realm]
  __e__authorize! Rack::Auth::Digest::MD5, *[opts], &proc
end

#engine(engine, engine_opts = {}) ⇒ Object

Examples:

  • use Haml for all actions

engine :Haml

  • use Haml only for :news and :articles actions

class App < E
  # ...
  setup :news, :articles do
    engine :Haml
  end
end

engine with opts

engine :Haml, :some_engine_argument, some_option: 'some value'

Parameters:

  • engine (Symbol)

    accepts any of Tilt supported engine

  • *args (String)

    any args to be passed to engine at initialization



21
22
23
24
25
26
27
# File 'lib/e-more/view/setup.rb', line 21

def engine engine, engine_opts = {}
  EUtils.register_extra_engines!
  engine = EConstants::VIEW__ENGINE_BY_SYM[engine] ||
    raise(ArgumentError, '%s engine not supported. Supported engines: %s' %
      [engine, EConstants::VIEW__ENGINE_BY_SYM.keys.join(', ')])
  @__e__engine = [engine, engine_opts].freeze
end

#engine?Boolean

Returns:

  • (Boolean)


28
29
30
# File 'lib/e-more/view/base.rb', line 28

def engine?
  @__e__engine || EConstants::VIEW__DEFAULT_ENGINE
end

#engine_ext(ext) ⇒ Object

set the extension used by templates



31
32
33
# File 'lib/e-more/view/setup.rb', line 31

def engine_ext ext
  @__e__engine_ext = ext.freeze
end

#engine_ext?Boolean

Returns:

  • (Boolean)


32
33
34
# File 'lib/e-more/view/base.rb', line 32

def engine_ext?
  @__e__engine_ext || EConstants::VIEW__EXT_BY_ENGINE[engine?.first] || ''
end

#engine_ext_with_formatObject



36
37
38
# File 'lib/e-more/view/base.rb', line 36

def engine_ext_with_format
  @__e__engine_ext_with_format ||= (format.to_s + engine_ext?).freeze
end

#envObject



9
10
11
# File 'lib/e-core/instance/base.rb', line 9

def env
  @__e__env
end

#error_handler_defined?(error_code) ⇒ Boolean

Returns:

  • (Boolean)


85
86
87
# File 'lib/e-core/instance/halt.rb', line 85

def error_handler_defined? error_code
  self.class.error_handler(error_code) || self.class.error_handler(:*)
end

#escape_element(*args) ⇒ Object



26
27
28
# File 'lib/e-core/instance/helpers.rb', line 26

def escape_element *args
  ::CGI.escapeElement *args
end

#escape_html(*args) ⇒ Object



18
19
20
# File 'lib/e-core/instance/helpers.rb', line 18

def escape_html *args
  ::CGI.escapeHTML *args
end

#evented_stream(keep_open = true, &proc) ⇒ Object Also known as: event_stream



13
14
15
16
# File 'lib/e-core/instance/stream.rb', line 13

def evented_stream keep_open = true, &proc
  content_type EConstants::CONTENT_TYPE__EVENT_STREAM
  streamer EStream::Evented, keep_open, &proc
end

#explicit_view_path(*args) ⇒ Object



60
61
62
# File 'lib/e-more/view/base.rb', line 60

def explicit_view_path *args
  EView__ExplicitPath.new File.join(*args)
end

#fetch(*args, &proc) ⇒ Object

same as ‘invoke` except it returns only body



87
88
89
90
91
# File 'lib/e-core/instance/invoke.rb', line 87

def fetch *args, &proc
  body = invoke(*args, &proc).last
  body = body.body if body.respond_to?(:body)
  body.respond_to?(:join) ? body.join : body
end

#flashObject

Examples:

flash[:alert] = 'Item Deleted'
p flash[:alert] #=> "Item Deleted"
p flash[:alert] #=> nil


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/e-core/instance/session.rb', line 42

def flash
  @__e__flash_proxy ||= Class.new do

    def initialize session = {}
      @session = session
    end

    def []= key, val
      @session[key(key)] = val
    end

    def [] key
      return unless val = @session[key = key(key)]
      @session.delete key
      val
    end

    def key key
      '__e__session__flash__-' << key.to_s
    end
  end.new env['rack.session']
end

#formatObject



58
59
60
# File 'lib/e-core/instance/base.rb', line 58

def format
  @__e__format
end

#formatsObject



179
180
181
# File 'lib/e-core/instance/base.rb', line 179

def formats
  self.class.formats action
end

#halt(*args) ⇒ Object

stop executing any code and send response to browser.

accepts an arbitrary number of arguments. if arg is an Integer, it will be used as status code. if arg is a Hash, it is treated as headers. if it is an array, it is treated as Rack response and are sent immediately, ignoring other args. any other args are treated as body.

Examples:

returning “Well Done” body with 200 status code

halt 'Well Done'

halting quietly, with empty body and 200 status code

halt

returning error 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)


28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/e-core/instance/halt.rb', line 28

def halt *args
  args.each do |a|
    case a
      when Fixnum
        response.status = a
      when Array
        status, headers, body = a
        response.status = status
        response.headers.update headers
        response.body = body
      when Hash
        response.headers.update a
      else
        response.body = [a.to_s]
    end
  end
  response.body ||= []
  throw :__e__catch__response__, response
end

#include(mdl) ⇒ Object



35
36
37
38
# File 'lib/e-core/e-core.rb', line 35

def include mdl
  native_include(mdl)
  (@__e__included_methods ||= []).concat mdl.public_instance_methods(false)
end

#initialize_controller(action = nil) ⇒ Object



5
6
7
# File 'lib/e-core/instance/base.rb', line 5

def initialize_controller action = nil
  @__e__action_passed_at_initialize = action
end

#invoke(*args) {|env| ... } ⇒ Object

Note:

unlike ‘pass`, `invoke` will not pass any data!

Note:

it will use current REQUEST_METHOD to issue a request. to use another request method use #[pass|invoke|fetch]via[verb] ex: #pass_via_get, #fetch_via_post etc

Note:

to update passed env, use a block. the block will receive the env as first argument and therefore you can update it as needed.

invoke some action via HTTP. to invoke an action on inner controller, pass controller as first argument and the action as second.

Parameters:

  • *args (Class)

Yields:



45
46
47
48
49
50
51
52
53
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
80
81
82
83
84
# File 'lib/e-core/instance/invoke.rb', line 45

def invoke *args

  if args.empty?
    body = '`invoke` expects some action(or a Controller and some action) to be provided'
    return [EConstants::STATUS__BAD_REQUEST, {}, [body]]
  end

  controller = EUtils.is_app?(args.first) ? args.shift : self.class

  if args.empty?
    body = 'Beside Controller, `invoke` expects some action to be provided'
    return [EConstants::STATUS__BAD_REQUEST, {}, [body]]
  end

  action = args.shift.to_sym
  unless route = controller[action]
    body = '%s does not respond to %s action' % [controller, action]
    return [EConstants::STATUS__NOT_FOUND, {}, [body]]
  end

  env = Hash[env()] # faster than #dup
  yield(env) if block_given?
  env[EConstants::ENV__SCRIPT_NAME]  = route
  env[EConstants::ENV__PATH_INFO]    = ''
  env[EConstants::ENV__QUERY_STRING] = ''
  env[EConstants::ENV__REQUEST_URI]  = ''
  env[EConstants::ENV__ESPRESSO_PATH_INFO] = nil

  if args.size > 0
    path, params = [''], {}
    args.each { |a| a.is_a?(Hash) ? params.update(a) : path << a }
    env[EConstants::ENV__PATH_INFO] = env[EConstants::ENV__REQUEST_URI] = path.join('/')
    
    if params.any?
      env.update(EConstants::ENV__QUERY_STRING => build_nested_query(params))
      env['rack.input'] = StringIO.new
    end
  end
  controller.new(action).call(env)
end

#invoke_actionObject



119
120
121
# File 'lib/e-core/instance/base.rb', line 119

def invoke_action
  self.send(action, *action_params__array)
end

#layout(layout = nil, &proc) ⇒ Object

Note:

by default no layout will be rendered. if you need layout, use ‘layout` to set it.

set the layout to be used by some or all actions.

Examples:

set :master layout for :index and :register actions


class Example < E
  setup :index, :register do
    layout :master
  end
end

instruct :plain and :json actions to not use layout


class Example < E
  setup :plain, :json do
    layout false
  end
end

use a block for layout


class Example < E
  layout do
    <<-HTML
        header
        <%= yield %>
        footer
    HTML
  end
end

Parameters:

  • layout (defaults to: nil)
  • &proc (Proc)


72
73
74
# File 'lib/e-more/view/setup.rb', line 72

def layout layout = nil, &proc
  @__e__layout = layout == false ? nil : [layout, proc].freeze
end

#layout?Boolean

Returns:

  • (Boolean)


40
41
42
# File 'lib/e-more/view/base.rb', line 40

def layout?
  @__e__layout
end

#layouts_path(path) ⇒ Object Also known as: layout_path

Note:

should be relative to view path

set custom path for layouts. default value: view path



116
117
118
# File 'lib/e-more/view/setup.rb', line 116

def layouts_path path
  @__e__layouts_path = path.freeze
end

#layouts_path?Boolean

Returns:

  • (Boolean)


24
25
26
# File 'lib/e-more/view/base.rb', line 24

def layouts_path?
  @__e__layouts_path || ''
end

#mime_type(type, fallback = nil) ⇒ Object

shortcut for Rack::Mime::MIME_TYPES.fetch



14
15
16
# File 'lib/e-core/instance/helpers.rb', line 14

def mime_type type, fallback = nil
  Rack::Mime::MIME_TYPES.fetch type, fallback
end

#native_includeObject



34
# File 'lib/e-core/e-core.rb', line 34

alias native_include include

#paramsObject



23
24
25
# File 'lib/e-core/instance/base.rb', line 23

def params
  @__e__params ||= EUtils.indifferent_params(request.params)
end

#pass(*args, &proc) ⇒ Object

simply pass control and data to another action or controller.

by default, it will pass control to an action on current controller. however, if first argument is a controller, control will be passed to it.

Examples:

pass control to #control_panel if user authorized

def index
  pass :control_panel if user?
end

passing with modified arguments and custom HTTP params

def index id, column
  pass :update, column, :value => id
end

passing control to inner controller

def index id
  pass Articles, :render_item, id
end

Parameters:

  • *args (Array)


25
26
27
28
# File 'lib/e-core/instance/invoke.rb', line 25

def pass *args, &proc
  args << params() unless args.any? {|a| a.is_a?(Hash)}
  halt invoke(*args, &proc)
end

#path_to_layouts(*args) ⇒ Object

returns full path to layouts. if any args given they are ‘File.join`-ed and appended to returned path.



56
57
58
# File 'lib/e-more/view/base.rb', line 56

def path_to_layouts *args
  explicit_view_path view_path?, layouts_path?, *args
end

#path_to_templates(*args) ⇒ Object

Note:

this method will not make use of ‘view_prefix`, thus you should provide full path to template, relative to `view_path` of course

returns full path to templates. if any args given they are ‘File.join`-ed and appended to returned path.



50
51
52
# File 'lib/e-more/view/base.rb', line 50

def path_to_templates *args
  explicit_view_path view_path?, *args
end

#permanent_redirect(*args) ⇒ Object

same as #redirect except it redirects with 301 status code



19
20
21
22
# File 'lib/e-core/instance/redirect.rb', line 19

def permanent_redirect *args
  delayed_redirect EConstants::STATUS__PERMANENT_REDIRECT, *args
  halt
end

#redirect(*args) ⇒ Object

stop any code execution and redirect right away with 302 status code. path is built by passing given args to route



13
14
15
16
# File 'lib/e-core/instance/redirect.rb', line 13

def redirect *args
  delayed_redirect EConstants::STATUS__REDIRECT, *args
  halt
end

#reload(params = nil) ⇒ Object

simply reload the page, using current GET params. to use custom GET params, pass a hash as first argument.

Parameters:

  • params (Hash, nil) (defaults to: nil)


7
8
9
# File 'lib/e-core/instance/redirect.rb', line 7

def reload params = nil
  redirect request.path, params || request.GET
end

#render(*args, &proc) ⇒ Object

render a template with layout(if any defined). if no template given, it will use current action name as template. extension will be automatically added, based on format and engine extension.



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/e-more/view/base.rb', line 67

def render *args, &proc
  template, scope, locals = __e__engine_arguments(args)
  engine_class, engine_opts = engine?
  engine_args = proc ? [engine_opts] : [__e__template(template), engine_opts]
  output = __e__engine_instance(engine_class, *engine_args, &proc).render(scope, locals)

  layout, layout_proc = layout?
  return output unless layout || layout_proc

  engine_args = layout_proc ? [engine_opts] : [__e__layout_template(layout), engine_opts]
  __e__engine_instance(engine_class, *engine_args, &layout_proc).render(scope, locals) { output }
end

#render_file(template, *args) ⇒ Object Also known as: render_f

render a template by name. it requires full template name, eg. with extension.



106
107
108
109
# File 'lib/e-more/view/base.rb', line 106

def render_file template, *args
  template = path_to_templates(template) unless template.instance_of?(EView__ExplicitPath)
  render_partial template, *args
end

#render_layout(*args, &proc) ⇒ Object Also known as: render_l

render a layout. if no layout given, it will use the layout defined for current action(if any). extension will be automatically added, based on format and engine extension.



94
95
96
97
98
99
100
101
# File 'lib/e-more/view/base.rb', line 94

def render_layout *args, &proc
  layout, scope, locals = __e__engine_arguments(args, nil)
  layout, layout_proc = layout ? layout : layout?
  layout || layout_proc || raise('No explicit layout given nor implicit layout found' % action)
  engine_class, engine_opts = engine?
  engine_args = layout_proc ? [engine_opts] : [__e__layout_template(layout), engine_opts]
  __e__engine_instance(engine_class, *engine_args, &layout_proc).render(scope, locals, &(proc || Proc.new {''}))
end

#render_layout_file(template, *args, &proc) ⇒ Object Also known as: render_lf

render a layout. it requires full layout name, eg. with extension.



114
115
116
117
# File 'lib/e-more/view/base.rb', line 114

def render_layout_file template, *args, &proc
  template = path_to_layouts(template) unless template.instance_of?(EView__ExplicitPath)
  render_layout template, *args, &proc
end

#render_partial(*args, &proc) ⇒ Object Also known as: render_p

render a template without layout. if no template given, it will use current action name as template. extension will be automatically added, based on format and engine extension.



83
84
85
86
87
88
# File 'lib/e-more/view/base.rb', line 83

def render_partial *args, &proc
  template, scope, locals = __e__engine_arguments(args)
  engine_class, engine_opts = engine?
  engine_args = proc ? [engine_opts] : [__e__template(template), engine_opts]
  __e__engine_instance(engine_class, *engine_args, &proc).render(scope, locals)
end

#requestObject Also known as: rq



13
14
15
# File 'lib/e-core/instance/base.rb', line 13

def request
  @__e__request
end

#request_token_auth(realm = 'Application') ⇒ Object Also known as: request_token_auth!



136
137
138
# File 'lib/e-core/instance/setup/auth.rb', line 136

def request_token_auth realm = 'Application'
  ETokenAuth.new(self).request_token_auth(realm)
end

#responseObject Also known as: rs



18
19
20
# File 'lib/e-core/instance/base.rb', line 18

def response
  @__e__response ||= EResponse.new
end

#route(*args) ⇒ Object



187
188
189
# File 'lib/e-core/instance/base.rb', line 187

def route *args
  self.class.route *args
end

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

Serving static files. Note that this blocks app while file readed/transmitted(on WEBrick and Thin, as minimum). To avoid app locking, setup your Nginx/Lighttpd server to set proper X-Sendfile header and use Rack::Sendfile middleware in your app.

Parameters:

  • path (String)

    full path to file

  • opts (Hash) (defaults to: {})

Options Hash (opts):

  • filename (String)

    the name of file displayed in browser’s save dialog

  • content_type (String)

    custom content_type

  • last_modified (String)
  • cache_control (String)
  • attachment (Boolean)

    if set to true, browser will prompt user to save file



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/e-core/instance/send_file.rb', line 15

def send_file path, opts = {}

  file = ::Rack::File.new nil
  file.path = path
  (cache_control = opts[:cache_control]) && (file.cache_control = cache_control)
  response = file.serving env

  response[1][EConstants::HEADER__CONTENT_DISPOSITION] = opts[:attachment] ?
      'attachment; filename="%s"' % (opts[:filename] || ::File.basename(path)) :
      'inline'

  (content_type = opts[:content_type]) &&
    (response[1][EConstants::HEADER__CONTENT_TYPE] = content_type)

  (last_modified = opts[:last_modified]) &&
    (response[1][EConstants::HEADER__LAST_MODIFIED] = last_modified)

  halt response
end

#send_files(dir) ⇒ Object

serve static files at dir path



36
37
38
# File 'lib/e-core/instance/send_file.rb', line 36

def send_files dir
  halt ::Rack::Directory.new(dir).call(env)
end

#sessionObject

a simple wrapper around Rack::Session



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/e-core/instance/session.rb', line 4

def session
  @__e__session_proxy ||= Class.new do

    def initialize session = {}
      @session = session
    end

    def [] key
      @session[key]
    end

    def []= key, val
      @session[key] = val
    end

    def keys
      @session.to_hash.keys
    end

    def values
      @session.to_hash.values
    end

    def delete key
      @session.delete key
    end

    def method_missing *args
      @session.send *args
    end

  end.new env['rack.session']
end

#setups(position) ⇒ Object



175
176
177
# File 'lib/e-core/instance/base.rb', line 175

def setups position
  self.class.setups position, action, format
end

#stream(keep_open = false, &proc) ⇒ Object



3
4
5
# File 'lib/e-core/instance/stream.rb', line 3

def stream keep_open = false, &proc
  streamer EStream::Generic, keep_open, &proc
end

#styled_halt(error_code = EConstants::STATUS__SERVER_ERROR, body = nil) ⇒ Object Also known as: styled_error, styled_error!, fail, fail!, quit, quit!, error, error!

same as ‘halt` except it carrying earlier defined error handlers. if no handler found it behaves exactly as `halt(error_code[, body])`.

Examples:

class App < E

  # defining the proc to be executed on 404 errors
  error 404 do |message|
    render_layout('layouts/404') { message }
  end

  def index id, status
    item = Model.fisrt(:id => id, :status => status)
    unless item
      # interrupt execution and send a styled 404 error to browser.
      styled_halt 404, 'Can not find item by given ID and Status'
    end
    # code to be executed only if item found
  end
end


69
70
71
72
73
74
75
# File 'lib/e-core/instance/halt.rb', line 69

def styled_halt error_code = EConstants::STATUS__SERVER_ERROR, body = nil
  if handler = error_handler_defined?(error_code)
    meth, arity = handler
    body = arity > 0 ? self.send(meth, body) : [self.send(meth), body].join
  end
  halt error_code.to_i, body
end

#token_auth(realm = 'Application', &proc) ⇒ Object

Makes it dead easy to do HTTP Token authentication.

class App < E
  before :set_account do
    authenticate
  end

  def 
    @account = Account.find_by ...
  end

  private
  def authenticate
    if accept? /xml|atom/
      if user = valid_token_auth? { |t, o| @account.users.authenticate(t, o) }
        @current_user = user
      else
        request_token_auth!
      end
    else
      # session based authentication
    end
  end
end

In your integration tests, you can do something like this:

def test_access_granted_from_xml
  get(
    "/notes/1.xml", nil,
    'HTTP_AUTHORIZATION' => EUtils.encode_token_auth_credentials('some-token')
  )

  assert_equal 200, status
end

On shared hosts, Apache sometimes doesn’t pass authentication headers to FCGI instances. If your environment matches this description and you cannot authenticate, try this rule in your Apache setup:

RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]

Examples:

simple Token example


class App < E
  TOKEN = "secret".freeze

  setup :edit do
    token_auth { |token| token == TOKEN }
  end

  def index
    "Everyone can see me!"
  end

  def edit
    "I'm only accessible if you know the password"
  end

end

more advanced Token example

where only Atom feeds and the XML API is protected by HTTP token authentication,
the regular HTML interface is protected by a session approach


126
127
128
# File 'lib/e-core/instance/setup/auth.rb', line 126

def token_auth realm = 'Application', &proc
  validate_token_auth(&proc) || request_token_auth(realm)
end

#transfer_encoding(encoding) ⇒ Object



46
47
48
# File 'lib/e-core/instance/setup/generic.rb', line 46

def transfer_encoding encoding
  response[EConstants::HEADER__TRANSFER_ENCODING] = encoding
end

#unescape_element(*args) ⇒ Object



30
31
32
# File 'lib/e-core/instance/helpers.rb', line 30

def unescape_element *args
  ::CGI.unescapeElement *args
end

#unescape_html(*args) ⇒ Object



22
23
24
# File 'lib/e-core/instance/helpers.rb', line 22

def unescape_html *args
  ::CGI.unescapeHTML *args
end

#userObject Also known as: user?



195
196
197
# File 'lib/e-core/instance/base.rb', line 195

def user
  env[EConstants::ENV__REMOTE_USER]
end

#validate_token_auth(&proc) ⇒ Object Also known as: valid_token_auth?



131
132
133
# File 'lib/e-core/instance/setup/auth.rb', line 131

def validate_token_auth &proc
  ETokenAuth.new(self).validate_token_auth(&proc)
end

#view_fullpath(path) ⇒ Object



84
85
86
# File 'lib/e-more/view/setup.rb', line 84

def view_fullpath path
  @__e__view_fullpath = path.freeze
end

#view_fullpath?Boolean

Returns:

  • (Boolean)


16
17
18
# File 'lib/e-more/view/base.rb', line 16

def view_fullpath?
  @__e__view_fullpath
end

#view_path(path) ⇒ Object

set custom path for templates. default value: app_root/view/



79
80
81
# File 'lib/e-more/view/setup.rb', line 79

def view_path path
  @__e__view_path = path.freeze
end

#view_path?Boolean

Returns:

  • (Boolean)


9
10
11
12
13
14
# File 'lib/e-more/view/base.rb', line 9

def view_path?
  @__e__computed_view_path ||= begin
    (fullpath = view_fullpath?) ? fullpath :
      File.join(app.root, @__e__view_path || EConstants::VIEW__DEFAULT_PATH).freeze
  end
end

#view_prefix(path) ⇒ Object

Note:

defaults to controller’s base_url

allow setting view prefix

class Reports < E
  map '/reports'
  view_prefix 'admin/reports'
  # ...
  def index
    render
  end

end

Examples:

:index action will render ‘view/admin/reports/index.EXT’ view,

regardless of base_url

Parameters:

  • string


107
108
109
# File 'lib/e-more/view/setup.rb', line 107

def view_prefix path
  @__e__view_prefix = path.freeze
end

#view_prefix?Boolean

Returns:

  • (Boolean)


20
21
22
# File 'lib/e-more/view/base.rb', line 20

def view_prefix?
  @__e__view_prefix || default_route
end

#websocket?Boolean

Returns:

  • (Boolean)


19
20
21
22
23
# File 'lib/e-core/instance/stream.rb', line 19

def websocket?
  # on websocket requests, Reel web-server storing the socket into ENV['rack.websocket']
  # TODO: implement rack.hijack API
  env[EConstants::RACK__WEBSOCKET]
end

#xhr?Boolean

Returns:

  • (Boolean)


9
10
11
# File 'lib/e-core/instance/helpers.rb', line 9

def xhr?
  (@__e__requested_with_map ||= {env["HTTP_X_REQUESTED_WITH"] => true})["XMLHttpRequest"]
end