Class: Cuba

Inherits:
Object
  • Object
show all
Defined in:
lib/cuba.rb,
lib/cuba/render.rb

Defined Under Namespace

Modules: Render Classes: Response

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&blk) ⇒ Cuba

Returns a new instance of Cuba.



102
103
104
105
# File 'lib/cuba.rb', line 102

def initialize(&blk)
  @blk = blk
  @captures = []
end

Instance Attribute Details

#capturesObject (readonly)

Returns the value of attribute captures.



100
101
102
# File 'lib/cuba.rb', line 100

def captures
  @captures
end

#envObject (readonly)

Returns the value of attribute env.



97
98
99
# File 'lib/cuba.rb', line 97

def env
  @env
end

#reqObject (readonly)

Returns the value of attribute req.



98
99
100
# File 'lib/cuba.rb', line 98

def req
  @req
end

#resObject (readonly)

Returns the value of attribute res.



99
100
101
# File 'lib/cuba.rb', line 99

def res
  @res
end

Class Method Details

.appObject



58
59
60
# File 'lib/cuba.rb', line 58

def self.app
  @app ||= Rack::Builder.new
end

.call(env) ⇒ Object



74
75
76
# File 'lib/cuba.rb', line 74

def self.call(env)
  prototype.call(env)
end

.deepclone(obj) ⇒ Object



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

def self.deepclone(obj)
  Marshal.load(Marshal.dump(obj))
end

.define(&block) ⇒ Object



66
67
68
# File 'lib/cuba.rb', line 66

def self.define(&block)
  app.run new(&block)
end

.inherited(child) ⇒ Object



93
94
95
# File 'lib/cuba.rb', line 93

def self.inherited(child)
  child.settings.replace(deepclone(settings))
end

.plugin(mixin) ⇒ Object



78
79
80
81
82
83
# File 'lib/cuba.rb', line 78

def self.plugin(mixin)
  include mixin
  extend  mixin::ClassMethods if defined?(mixin::ClassMethods)

  mixin.setup(self) if mixin.respond_to?(:setup)
end

.prototypeObject



70
71
72
# File 'lib/cuba.rb', line 70

def self.prototype
  @prototype ||= app.to_app
end

.reset!Object



53
54
55
56
# File 'lib/cuba.rb', line 53

def self.reset!
  @app = nil
  @prototype = nil
end

.settingsObject



85
86
87
# File 'lib/cuba.rb', line 85

def self.settings
  @settings ||= {}
end

.use(middleware, *args, &block) ⇒ Object



62
63
64
# File 'lib/cuba.rb', line 62

def self.use(middleware, *args, &block)
  app.use(middleware, *args, &block)
end

Instance Method Details

#accept(mimetype) ⇒ Object

If you want to match against the HTTP_ACCEPT value.

Examples:

# HTTP_ACCEPT=application/xml
on accept("application/xml") do
  # automatically set to application/xml.
  res.write res["Content-Type"]
end


269
270
271
272
273
274
275
276
277
# File 'lib/cuba.rb', line 269

def accept(mimetype)
  lambda do
    accept = String(env["HTTP_ACCEPT"]).split(",")

    if accept.any? { |s| s.strip == mimetype }
      res["Content-Type"] = mimetype
    end
  end
end

#call(env) ⇒ Object



111
112
113
# File 'lib/cuba.rb', line 111

def call(env)
  dup.call!(env)
end

#call!(env) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/cuba.rb', line 115

def call!(env)
  @env = env
  @req = settings[:req].new(env)
  @res = settings[:res].new

  # This `catch` statement will either receive a
  # rack response tuple via a `halt`, or will
  # fall back to issuing a 404.
  #
  # When it `catch`es a throw, the return value
  # of this whole `call!` method will be the
  # rack response tuple, which is exactly what we want.
  catch(:halt) do
    instance_eval(&@blk)

    res.status = 404
    res.finish
  end
end

#defaultObject

Syntactic sugar for providing catch-all matches.

Examples:

on default do
  res.write "404"
end


285
286
287
# File 'lib/cuba.rb', line 285

def default
  true
end

#deleteObject



312
# File 'lib/cuba.rb', line 312

def delete; req.delete? end

#extension(ext = "\\w+") ⇒ Object

A matcher for files with a certain extension.

Examples:

# PATH_INFO=/style/app.css
on "style", extension("css") do |file|
  res.write file # writes app
end


231
232
233
# File 'lib/cuba.rb', line 231

def extension(ext = "\\w+")
  lambda { consume("([^\\/]+?)\.#{ext}\\z") }
end

#getObject

Syntatic sugar for providing HTTP Verb matching.

Examples:

on get, "signup" do
end

on post, "signup" do
end


309
# File 'lib/cuba.rb', line 309

def get;    req.get?    end

#halt(response) ⇒ Object



331
332
333
# File 'lib/cuba.rb', line 331

def halt(response)
  throw :halt, response
end

#header(key) ⇒ Object



247
248
249
# File 'lib/cuba.rb', line 247

def header(key)
  lambda { env[key.upcase.tr("-","_")] }
end

#host(hostname) ⇒ Object

Useful for matching against the request host (i.e. HTTP_HOST).

Examples:

on host("account1.example.com"), "api" do
  res.write "You have reached the API of account1."
end


257
258
259
# File 'lib/cuba.rb', line 257

def host(hostname)
  hostname === req.host
end

#match(matcher, segment = "([^\\/]+)") ⇒ Object



213
214
215
216
217
218
219
220
221
222
# File 'lib/cuba.rb', line 213

def match(matcher, segment = "([^\\/]+)")
  case matcher
  when String then consume(matcher.gsub(/:\w+/, segment))
  when Regexp then consume(matcher)
  when Symbol then consume(segment)
  when Proc   then matcher.call
  else
    matcher
  end
end

#on(*args, &block) ⇒ Object

The heart of the path / verb / any condition matching.

Examples:


on get do
  res.write "GET"
end

on get, "signup" do
  res.write "Signup"
end

on "user/:id" do |uid|
  res.write "User: #{uid}"
end

on "styles", extension("css") do |file|
  res.write render("styles/#{file}.sass")
end


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/cuba.rb', line 161

def on(*args, &block)
  try do
    # For every block, we make sure to reset captures so that
    # nesting matchers won't mess with each other's captures.
    @captures = []

    # We stop evaluation of this entire matcher unless
    # each and every `arg` defined for this matcher evaluates
    # to a non-false value.
    #
    # Short circuit examples:
    #    on true, false do
    #
    #    # PATH_INFO=/user
    #    on true, "signup"
    return unless args.all? { |arg| match(arg) }

    # The captures we yield here were generated and assembled
    # by evaluating each of the `arg`s above. Most of these
    # are carried out by #consume.
    yield(*captures)

    halt res.finish
  end
end

#param(key) ⇒ Object

Used to ensure that certain request parameters are present. Acts like a precondition / assertion for your route.

Examples:

# POST with data like user[fname]=John&user[lname]=Doe
on "signup", param("user") do |atts|
  User.create(atts)
end


243
244
245
# File 'lib/cuba.rb', line 243

def param(key)
  lambda { captures << req[key] unless req[key].to_s.empty? }
end

#postObject



310
# File 'lib/cuba.rb', line 310

def post;   req.post?   end

#putObject



311
# File 'lib/cuba.rb', line 311

def put;    req.put?    end

#rootObject

Access the root of the application.

Examples:


# GET /
on root do
  res.write "Home"
end


297
298
299
# File 'lib/cuba.rb', line 297

def root
  env["PATH_INFO"] == "/" || env["PATH_INFO"] == ""
end

#run(app) ⇒ Object

If you want to halt the processing of an existing handler and continue it via a different handler.

Examples:

def redirect(*args)
  run Cuba.new { on(default) { res.redirect(*args) }}
end

on "account" do
  redirect "/login" unless session["uid"]

  res.write "Super secure account info."
end


327
328
329
# File 'lib/cuba.rb', line 327

def run(app)
  halt app.call(req.env)
end

#sessionObject



135
136
137
138
139
# File 'lib/cuba.rb', line 135

def session
  env["rack.session"] || raise(RuntimeError,
    "You're missing a session handler. You can get started " +
    "by adding Cuba.use Rack::Session::Cookie")
end

#settingsObject



107
108
109
# File 'lib/cuba.rb', line 107

def settings
  self.class.settings
end