Class: Cuba

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

Defined Under Namespace

Classes: RedefinitionError

Constant Summary collapse

VERSION =
"2.1.0"
@@methods =
[]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&blk) ⇒ Cuba

Returns a new instance of Cuba.



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

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

Instance Attribute Details

#capturesObject (readonly)

Returns the value of attribute captures.



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

def captures
  @captures
end

#envObject (readonly)

Returns the value of attribute env.



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

def env
  @env
end

#reqObject (readonly)

Returns the value of attribute req.



56
57
58
# File 'lib/cuba.rb', line 56

def req
  @req
end

#resObject (readonly)

Returns the value of attribute res.



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

def res
  @res
end

Class Method Details

.appObject



31
32
33
# File 'lib/cuba.rb', line 31

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

.buildObject



43
44
45
# File 'lib/cuba.rb', line 43

def self.build
  Class.new(self)
end

.call(env) ⇒ Object



51
52
53
# File 'lib/cuba.rb', line 51

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

.define(&block) ⇒ Object



39
40
41
# File 'lib/cuba.rb', line 39

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

.method_added(meth) ⇒ Object

In order to prevent people from overriding the standard Cuba methods like ‘get`, `put`, etc, we add this as a safety measure.



300
301
302
# File 'lib/cuba.rb', line 300

def self.method_added(meth)
  @@methods << meth
end

.prototypeObject



47
48
49
# File 'lib/cuba.rb', line 47

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

.reset!Object



26
27
28
29
# File 'lib/cuba.rb', line 26

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

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



35
36
37
# File 'lib/cuba.rb', line 35

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

Instance Method Details

#_call(env) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/cuba.rb', line 69

def _call(env)
  @env = env
  @req = Rack::Request.new(env)
  @res = Rack::Response.new
  @matched = false

  catch(:ron_run_next_app) do
    instance_eval(&@blk)

    @res.status = 404 unless @matched || !@res.empty?

    return @res.finish
  end.call(env)
end

#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


251
252
253
254
255
256
# File 'lib/cuba.rb', line 251

def accept(mimetype)
  lambda do
    String(env["HTTP_ACCEPT"]).split(",").any? { |s| s.strip == mimetype } and
      res["Content-Type"] = mimetype
  end
end

#call(env) ⇒ Object



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

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

#defaultObject

Syntactic sugar for providing catch-all matches.

Examples:

on default do
  res.write "404"
end


264
265
266
# File 'lib/cuba.rb', line 264

def default
  true
end

#deleteObject



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

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


213
214
215
# File 'lib/cuba.rb', line 213

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


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

def get    ; req.get?    end

#header(key) ⇒ Object



229
230
231
# File 'lib/cuba.rb', line 229

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


239
240
241
# File 'lib/cuba.rb', line 239

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

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



195
196
197
198
199
200
201
202
203
204
# File 'lib/cuba.rb', line 195

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


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
164
165
166
167
168
169
# File 'lib/cuba.rb', line 133

def on(*args, &block)
  # No use running any other matchers if we've already found a
  # proper matcher.
  return if @matched

  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) }

    begin
      # 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

    ensure
      # Regardless of what happens in the `yield`, we should ensure that
      # we successfully set `@matched` to true.

      # At this point, we've successfully matched with some corresponding
      # matcher, so we can skip all other matchers defined.
      @matched = true
    end
  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


225
226
227
# File 'lib/cuba.rb', line 225

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

#postObject



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

def post   ; req.post?   end

#putObject



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

def put    ; req.put?    end

#render(template, locals = {}, options = {}, &block) ⇒ Object

Render any type of template file supported by Tilt.

Examples:


# Renders home, and is assumed to be HAML.
render("home.haml")

# Renders with some local variables
render("home.haml", site_name: "My Site")

# Renders with HAML options
render("home.haml", {}, ugly: true, format: :html5)

# Renders in layout
render("layout.haml") { render("home.haml") }


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

def render(template, locals = {}, options = {}, &block)
  _cache.fetch(template, locals) {
    Tilt.new(template, 1, options)
  }.render(self, locals, &block)
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


294
295
296
# File 'lib/cuba.rb', line 294

def run(app)
  throw :ron_run_next_app, app
end