Class: Cyberweb::REST::Base

Inherits:
Object
  • Object
show all
Includes:
Helpers, Templates, Rack::Utils
Defined in:
lib/cyberweb/REST/base/base.rb

Overview

Cyberweb::REST::Base

Direct Known Subclasses

Application

Constant Summary collapse

URI_INSTANCE =
#

URI_INSTANCE

#
URI::Parser.new
CALLERS_TO_IGNORE =

CALLERS_TO_IGNORE

[
  %r{/sinatra(/(base|main|show_exceptions))?\.rb$},   # all cyberweb-rest code
  %r{lib/tilt.*\.rb$},                                # all tilt code
  /^\(.*\)$/,                                         # generated code
  %r{rubygems/(custom|core_ext/kernel)_require\.rb$}, # rubygems require hacks
  /active_support/,                                   # active_support require hacks
  %r{bundler(/(?:runtime|inline))?\.rb},              # bundler require hacks
  /<internal:/                                        # internal in ruby >= 1.9.2
]

Constants included from Helpers

Helpers::ETAG_KINDS

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Templates

#asciidoc, #builder, #erb, #find_template, #haml, #liquid, #markaby, #markdown, #nokogiri, #rabl, #rdoc, #slim, #yajl

Methods included from Helpers

#attachment, #back, #bad_request?, #body, #cache_control, #client_error?, #content_type, #error, #etag, #expires, #headers, #informational?, #last_modified, #logger, #mime_type, #not_found, #not_found?, #redirect, #redirect?, #send_file, #server_error?, #session, #status, #stream, #success?, #time_for, #uri

Constructor Details

#initialize(app = nil, **_kwargs) {|_self| ... } ⇒ Base

#

initialize

#

Yields:

  • (_self)

Yield Parameters:



50
51
52
53
54
55
56
# File 'lib/cyberweb/REST/base/base.rb', line 50

def initialize(app = nil, **_kwargs)
  super()
  @app = app
  @template_cache = Tilt::Cache.new
  @pinned_response = nil # whether a before! filter pinned the content-type
  yield self if block_given?
end

Class Attribute Details

.errorsObject (readonly)

Returns the value of attribute errors.



408
409
410
# File 'lib/cyberweb/REST/base/base.rb', line 408

def errors
  @errors
end

.filtersObject (readonly)

Returns the value of attribute filters.



406
407
408
# File 'lib/cyberweb/REST/base/base.rb', line 406

def filters
  @filters
end

.routesObject (readonly)

Returns the value of attribute routes.



405
406
407
# File 'lib/cyberweb/REST/base/base.rb', line 405

def routes
  @routes
end

.templatesObject (readonly)

Returns the value of attribute templates.



407
408
409
# File 'lib/cyberweb/REST/base/base.rb', line 407

def templates
  @templates
end

Instance Attribute Details

#appObject

Returns the value of attribute app.



40
41
42
# File 'lib/cyberweb/REST/base/base.rb', line 40

def app
  @app
end

#envObject

Returns the value of attribute env.



41
42
43
# File 'lib/cyberweb/REST/base/base.rb', line 41

def env
  @env
end

#paramsObject

Returns the value of attribute params.



44
45
46
# File 'lib/cyberweb/REST/base/base.rb', line 44

def params
  @params
end

#requestObject

Returns the value of attribute request.



42
43
44
# File 'lib/cyberweb/REST/base/base.rb', line 42

def request
  @request
end

#responseObject

Returns the value of attribute response.



43
44
45
# File 'lib/cyberweb/REST/base/base.rb', line 43

def response
  @response
end

#template_cacheObject (readonly)

Returns the value of attribute template_cache.



45
46
47
# File 'lib/cyberweb/REST/base/base.rb', line 45

def template_cache
  @template_cache
end

Class Method Details

.add_filter(type, path = /.*/, **options, &block) ⇒ Object

add a filter



595
596
597
# File 'lib/cyberweb/REST/base/base.rb', line 595

def add_filter(type, path = /.*/, **options, &block)
  filters[type] << compile!(type, path, block, **options)
end

.after(path = /.*/, **options, &block) ⇒ Object

Define an after filter; runs after all requests within the same context as route handlers and may access/modify the request and response.



590
591
592
# File 'lib/cyberweb/REST/base/base.rb', line 590

def after(path = /.*/, **options, &block)
  add_filter(:after, path, **options, &block)
end

.before(path = /.*/, **options, &block) ⇒ Object

Define a before filter; runs before all requests within the same context as route handlers and may access/modify the request and response.



583
584
585
# File 'lib/cyberweb/REST/base/base.rb', line 583

def before(path = /.*/, **options, &block)
  add_filter(:before, path, **options, &block)
end

.build(app) ⇒ Object

Creates a Rack::Builder instance with all the middleware set up and the given app as end point.



742
743
744
745
746
747
748
# File 'lib/cyberweb/REST/base/base.rb', line 742

def build(app)
  builder = Rack::Builder.new
  setup_default_middleware builder
  setup_middleware builder
  builder.run app
  builder
end

.call(env) ⇒ Object



750
751
752
# File 'lib/cyberweb/REST/base/base.rb', line 750

def call(env)
  synchronize { prototype.call(env) }
end

.caller_filesObject

Like Kernel#caller but excluding certain magic entries and without line / method information; the resulting array contains filenames only.



756
757
758
# File 'lib/cyberweb/REST/base/base.rb', line 756

def caller_files
  cleaned_caller(1).flatten
end

.condition(name = "#{caller.first[/`.*'/]} condition", &block) ⇒ Object

Add a route condition. The route is considered non-matching when the block returns false.



601
602
603
# File 'lib/cyberweb/REST/base/base.rb', line 601

def condition(name = "#{caller.first[/`.*'/]} condition", &block)
  @conditions << generate_method(name, &block)
end

.configure(*envs) {|_self| ... } ⇒ Object

configure

Set configuration options for Sinatra and/or the app. Allows scoping of settings for certain environments.

Yields:

  • (_self)

Yield Parameters:



670
671
672
# File 'lib/cyberweb/REST/base/base.rb', line 670

def configure(*envs)
  yield self if envs.empty? || envs.include?(environment.to_sym)
end

.delete(path, opts = {}, &block) ⇒ Object



632
# File 'lib/cyberweb/REST/base/base.rb', line 632

def delete(path, opts = {}, &block)  route 'DELETE',  path, opts, &block end

.development?Boolean

Returns:

  • (Boolean)


662
# File 'lib/cyberweb/REST/base/base.rb', line 662

def development?; environment == :development end

.disable(*opts) ⇒ Object

Same as calling ‘set :option, false` for each of the given options.



496
497
498
# File 'lib/cyberweb/REST/base/base.rb', line 496

def disable(*opts)
  opts.each { |key| set(key, false) }
end

.enable(*opts) ⇒ Object

Same as calling ‘set :option, true` for each of the given options.



491
492
493
# File 'lib/cyberweb/REST/base/base.rb', line 491

def enable(*opts)
  opts.each { |key| set(key, true) }
end

.error(*codes, &block) ⇒ Object

Define a custom error handler. Optionally takes either an Exception class, or an HTTP status code to specify which errors should be handled.



503
504
505
506
507
508
509
# File 'lib/cyberweb/REST/base/base.rb', line 503

def error(*codes, &block)
  args  = compile! 'ERROR', /.*/, block
  codes = codes.flat_map(&method(:Array))
  codes << Exception if codes.empty?
  codes << ::Cyberweb::REST::NotFound if codes.include?(404)
  codes.each { |c| (@errors[c] ||= []) << args }
end

.extensionsObject

Extension modules registered on this class and all superclasses.



431
432
433
434
435
436
437
# File 'lib/cyberweb/REST/base/base.rb', line 431

def extensions
  if superclass.respond_to?(:extensions)
    (@extensions + superclass.extensions).uniq
  else
    @extensions
  end
end

.get(path, opts = {}, &block) ⇒ Object

Defining a ‘GET` handler also automatically defines a `HEAD` handler.



620
621
622
623
624
625
626
# File 'lib/cyberweb/REST/base/base.rb', line 620

def get(path, opts = {}, &block)
  conditions = @conditions.dup
  route('GET', path, opts, &block)

  @conditions = conditions
  route('HEAD', path, opts, &block)
end

.head(path, opts = {}, &block) ⇒ Object



634
# File 'lib/cyberweb/REST/base/base.rb', line 634

def head(path, opts = {}, &block)    route 'HEAD',    path, opts, &block end

.helpers(*extensions, &block) ⇒ Object

Makes the methods defined in the block and in the Modules given in ‘extensions` available to the handlers and templates



646
647
648
649
# File 'lib/cyberweb/REST/base/base.rb', line 646

def helpers(*extensions, &block)
  class_eval(&block)   if block_given?
  include(*extensions) if extensions.any?
end

.inline_templates=(file = nil) ⇒ Object

Load embedded templates from the file; uses the caller’s __FILE__ when no file is specified.



529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
# File 'lib/cyberweb/REST/base/base.rb', line 529

def inline_templates=(file = nil)
  file = (caller_files.first || File.expand_path($0)) if file.nil? || file == true

  begin
    io = ::IO.respond_to?(:binread) ? ::IO.binread(file) : ::IO.read(file)
    app, data = io.gsub("\r\n", "\n").split(/^__END__$/, 2)
  rescue Errno::ENOENT
    app, data = nil
  end

  return unless data

  encoding = if app && app =~ /([^\n]*\n)?#[^\n]*coding: *(\S+)/m
               $2
             else
               settings.default_encoding
             end

  lines = app.count("\n") + 1
  template = nil
  force_encoding data, encoding
  data.each_line do |line|
    lines += 1
    if line =~ /^@@\s*(.*\S)\s*$/
      template = force_encoding(String.new, encoding)
      templates[$1.to_sym] = [template, file, lines]
    elsif template
      template << line
    end
  end
end

.layout(name = :layout, &block) ⇒ Object

Define the layout template. The block must return the template source.



523
524
525
# File 'lib/cyberweb/REST/base/base.rb', line 523

def layout(name = :layout, &block)
  template name, &block
end


640
# File 'lib/cyberweb/REST/base/base.rb', line 640

def link(path, opts = {}, &block)    route 'LINK',    path, opts, &block end

.middlewareObject

Middleware used in this class and all superclasses.



440
441
442
443
444
445
446
# File 'lib/cyberweb/REST/base/base.rb', line 440

def middleware
  if superclass.respond_to?(:middleware)
    superclass.middleware + @middleware
  else
    @middleware
  end
end

.mime_type(type, value = nil) ⇒ Object

Lookup or register a mime type in Rack’s mime registry.



562
563
564
565
566
567
568
569
570
# File 'lib/cyberweb/REST/base/base.rb', line 562

def mime_type(type, value = nil)
  return type      if type.nil?
  return type.to_s if type.to_s.include?('/')

  type = ".#{type}" unless type.to_s[0] == '.'
  return Rack::Mime.mime_type(type, nil) unless value

  Rack::Mime::MIME_TYPES[type] = value
end

.mime_types(type) ⇒ Object

provides all mime types matching type, including deprecated types:

mime_types :html # => ['text/html']
mime_types :js   # => ['application/javascript', 'text/javascript']


575
576
577
578
# File 'lib/cyberweb/REST/base/base.rb', line 575

def mime_types(type)
  type = mime_type type
  type =~ %r{^application/(xml|javascript)$} ? [type, "text/#{$1}"] : [type]
end

.new(*args, &block) ⇒ Object

Create a new instance of the class fronted by its middleware pipeline. The object is guaranteed to respond to #call but may not be an instance of the class new was called on.



734
735
736
737
# File 'lib/cyberweb/REST/base/base.rb', line 734

def new(*args, &block)
  instance = new!(*args, &block)
  Wrapper.new(build(instance).to_app, instance)
end

.not_found(&block) ⇒ Object

Sugar for ‘error(404) { … }`



512
513
514
# File 'lib/cyberweb/REST/base/base.rb', line 512

def not_found(&block)
  error(404, &block)
end

.options(path, opts = {}, &block) ⇒ Object



636
# File 'lib/cyberweb/REST/base/base.rb', line 636

def options(path, opts = {}, &block) route 'OPTIONS', path, opts, &block end

.patch(path, opts = {}, &block) ⇒ Object



638
# File 'lib/cyberweb/REST/base/base.rb', line 638

def patch(path, opts = {}, &block)   route 'PATCH',   path, opts, &block end

.post(path, opts = {}, &block) ⇒ Object



630
# File 'lib/cyberweb/REST/base/base.rb', line 630

def post(path, opts = {}, &block)    route 'POST',    path, opts, &block end

.production?Boolean

Returns:

  • (Boolean)


663
# File 'lib/cyberweb/REST/base/base.rb', line 663

def production?;  environment == :production  end

.prototypeObject

The prototype instance used to process requests.



724
725
726
# File 'lib/cyberweb/REST/base/base.rb', line 724

def prototype
  @prototype ||= new
end

.public=(value) ⇒ Object



605
606
607
608
# File 'lib/cyberweb/REST/base/base.rb', line 605

def public=(value)
  warn_for_deprecation ':public is no longer used to avoid overloading Module#public, use :public_folder or :public_dir instead'
  set(:public_folder, value)
end

.public_dirObject



614
615
616
# File 'lib/cyberweb/REST/base/base.rb', line 614

def public_dir
  public_folder
end

.public_dir=(value) ⇒ Object



610
611
612
# File 'lib/cyberweb/REST/base/base.rb', line 610

def public_dir=(value)
  self.public_folder = value
end

.put(path, opts = {}, &block) ⇒ Object



628
# File 'lib/cyberweb/REST/base/base.rb', line 628

def put(path, opts = {}, &block)     route 'PUT',     path, opts, &block end

.quit!Object Also known as: stop!

Stop the self-hosted server if running.



682
683
684
685
686
687
688
689
690
# File 'lib/cyberweb/REST/base/base.rb', line 682

def quit!
  return unless running?

  # Use Thin's hard #stop! if available, otherwise just #stop.
  running_server.respond_to?(:stop!) ? running_server.stop! : running_server.stop
  warn '== Cyberweb::REST has ended his set (crowd applauds)' unless suppress_messages?
  set :running_server, nil
  set :handler_name, nil
end

.register(*extensions, &block) ⇒ Object

Register an extension. Alternatively take a block from which an extension will be created and registered on the fly.



653
654
655
656
657
658
659
660
# File 'lib/cyberweb/REST/base/base.rb', line 653

def register(*extensions, &block)
  extensions << Module.new(&block) if block_given?
  @extensions += extensions
  extensions.each do |extension|
    extend extension
    extension.registered(self) if extension.respond_to?(:registered)
  end
end

.reset!Object

reset!

Removes all routes, filters, middleware and extension hooks from the current class (not routes/filters/… defined by its superclass).



414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
# File 'lib/cyberweb/REST/base/base.rb', line 414

def reset!
  @conditions     = []
  @routes         = {}
  @filters        = { before: [], after: [] }
  @errors         = {}
  @middleware     = []
  @prototype      = nil
  @extensions     = []

  @templates = if superclass.respond_to?(:templates)
                 Hash.new { |_hash, key| superclass.templates[key] }
               else
                 {}
               end
end

.run!(options = {}, &block) ⇒ Object Also known as: start!

run

Run the CyberweB::REST app as a self-hosted server using Puma, Falcon, Mongrel, or WEBrick (in that order). If given a block, will call with the constructed handler once we have taken the stage.



697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
# File 'lib/cyberweb/REST/base/base.rb', line 697

def run!(options = {}, &block)
  return if running?

  set options
  handler         = Rack::Handler.pick(server)
  handler_name    = handler.name.gsub(/.*::/, '')
  server_settings = settings.respond_to?(:server_settings) ? settings.server_settings : {}
  server_settings.merge!(Port: port, Host: bind)

  begin
    start_server(handler, server_settings, handler_name, &block)
  rescue Errno::EADDRINUSE
    warn "== Someone is already performing on port #{port}!"
    raise
  ensure
    quit!
  end
end

.running?Boolean

Check whether the self-hosted server is running or not.

Returns:

  • (Boolean)


719
720
721
# File 'lib/cyberweb/REST/base/base.rb', line 719

def running?
  running_server?
end

.set(option, value = (not_set = true), ignore_setter = false, &block) ⇒ Object

Sets an option to the given value. If the value is a proc, the proc will be called every time the option is accessed.

Raises:

  • (ArgumentError)


450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
# File 'lib/cyberweb/REST/base/base.rb', line 450

def set(option, value = (not_set = true), ignore_setter = false, &block)
  raise ArgumentError if block && !not_set

  if block
    value = block
    not_set = false
  end

  if not_set
    raise ArgumentError unless option.respond_to?(:each)

    option.each { |k, v| set(k, v) }
    return self
  end

  if respond_to?("#{option}=") && !ignore_setter
    return __send__("#{option}=", value)
  end

  setter = proc { |val| set option, val, true }
  getter = proc { value }

  case value
  when Proc
    getter = value
  when Symbol, Integer, FalseClass, TrueClass, NilClass
    getter = value.inspect
  when Hash
    setter = proc do |val|
      val = value.merge val if Hash === val
      set option, val, true
    end
  end

  define_singleton("#{option}=", setter)
  define_singleton(option, getter)
  define_singleton("#{option}?", "!!#{option}") unless method_defined? "#{option}?"
  self
end

.settingsObject

#

Access settings defined with Base.set.

#


101
102
103
# File 'lib/cyberweb/REST/base/base.rb', line 101

def self.settings
  self
end

.template(name, &block) ⇒ Object

Define a named template. The block must return the template source.



517
518
519
520
# File 'lib/cyberweb/REST/base/base.rb', line 517

def template(name, &block)
  filename, line = caller_locations.first
  templates[name] = [block, filename, line.to_i]
end

.test?Boolean

Returns:

  • (Boolean)


664
# File 'lib/cyberweb/REST/base/base.rb', line 664

def test?;        environment == :test        end


642
# File 'lib/cyberweb/REST/base/base.rb', line 642

def unlink(path, opts = {}, &block)  route 'UNLINK',  path, opts, &block end

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

Use the specified Rack middleware



675
676
677
678
# File 'lib/cyberweb/REST/base/base.rb', line 675

def use(middleware, *args, &block)
  @prototype = nil
  @middleware << [middleware, args, block]
end

Instance Method Details

#call(env) ⇒ Object

#

call

Rack call interface.

#


70
71
72
# File 'lib/cyberweb/REST/base/base.rb', line 70

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

#call!(env) ⇒ Object

#

call!

#


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/cyberweb/REST/base/base.rb', line 77

def call!(env)
  @env      = env
  @params   = {}
  @request  = ::Cyberweb::REST::Request.new(env)
  @response = ::Cyberweb::REST::Response.new
  @pinned_response = nil
  template_cache.clear if settings.reload_templates

  invoke { dispatch! }
  invoke { error_block!(response.status) } unless @env['sinatra.error']

  unless @response['Content-Type']
    if Array === body && body[0].respond_to?(:content_type)
      content_type body[0].content_type
    elsif (default = settings.default_content_type)
      content_type default
    end
  end
  @response.finish
end

#forwardObject

#

forward

Forward the request to the downstream app – middleware only.

#


142
143
144
145
146
147
148
149
# File 'lib/cyberweb/REST/base/base.rb', line 142

def forward
  raise 'downstream app not set' unless @app.respond_to? :call
  status, headers, body = @app.call env
  @response.status = status
  @response.body = body
  @response.headers.merge! headers
  nil
end

#halt(*response) ⇒ Object

#

halt

Exit the current block, halts any further processing of the request, and returns the specified response.

#


120
121
122
123
# File 'lib/cyberweb/REST/base/base.rb', line 120

def halt(*response)
  response = response.first if response.length == 1
  throw :halt, response
end

#new!Object

Create a new instance without middleware in front of it.



729
# File 'lib/cyberweb/REST/base/base.rb', line 729

alias new! new

#pass(&block) ⇒ Object

#

pass

Pass control to the next matching route.

If there are no more matching routes, Cyberweb::REST will return a 404 response.

#


133
134
135
# File 'lib/cyberweb/REST/base/base.rb', line 133

def pass(&block)
  throw :pass, block
end

#settingsObject

#

settings

Access settings defined with Base.set.

#


110
111
112
# File 'lib/cyberweb/REST/base/base.rb', line 110

def settings
  self.class.settings
end

#template_cache?Boolean

#

template_cache?

#

Returns:

  • (Boolean)


61
62
63
# File 'lib/cyberweb/REST/base/base.rb', line 61

def template_cache?
  @template_cache
end