Class: Orange::Packet

Inherits:
Object show all
Defined in:
lib/orange-core/packet.rb

Overview

Orange::Packet is a wrapper for Rack’s basic env variable. It acts somewhat like Rack::Request, except with more functionality. For each request a unique Packet is generated, and this packet is used to by middleware to create the response.

All orange enhanced middleware has a packet_call method that automatically turns the generic rack call(env) into a call that has a packet instead, so all functions for the packet should be available for the request.

Pulps are modules that are mixed into the Packet, allowing additional functionality to be used by the packet.

By default, haml files are parsed in the context of their packet. This means all of instance variables and functions should be available to the haml parser.

Constant Summary collapse

DEFAULT_HEADERS =

By default, header will be content-type

{"Content-Type" => 'text/html'}

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(orange, env) ⇒ Packet

Initialize is only called if a packet hasn’t already been called for this env. Sets up the basic env, creating a pointer back to self and a Rack::Request object.

Parameters:

  • orange (Orange::Core)

    a pointer to the orange core

  • env (Hash)

    a standard Rack hash



56
57
58
59
60
61
62
63
# File 'lib/orange-core/packet.rb', line 56

def initialize(orange, env)
  @orange = orange
  @env = env
  @env['orange.packet'] = self
  @env['orange.env'] = {} unless @env['orange.env']
  @env['orange.env'][:request] = Rack::Request.new(env)
  @env['orange.env'][:headers] = {}
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(id, *args) ⇒ Object

Method Missing allows defining custom methods

Raises:

  • (NoMethodError)


221
222
223
224
225
226
227
228
229
230
# File 'lib/orange-core/packet.rb', line 221

def method_missing(id, *args)
  matched = false
  id = id.to_s
  @@matchers.each_key do |k|
    matched = k if id =~ k
    break if matched
  end
  return @@matchers[matched].call(packet, matched.match(id), args) if matched
  raise NoMethodError.new("No method ##{id} found", id)
end

Class Method Details

.meta_methods(regex) {|Orange::Packet, MatchData, args| ... } ⇒ Object

Allows tying in to the method_missing method without redefining it elsewhere. This lets dynamic methods be defined on the packet. Regexes are defined to match method names. #method_missing will loop through and try to find a match, executing the proc defined in the block.

Parameters:

  • regex (Regexp)

    the regex to match

Yields:

  • (Orange::Packet, MatchData, args)

    the block to execute if matched (passed instance, match data and args)



38
39
40
41
42
43
# File 'lib/orange-core/packet.rb', line 38

def self.meta_methods(regex, &block)
  return unless block_given?
  proc = block
  @@matchers ||= {}
  @@matchers[regex] = proc
end

.mixin(inc) ⇒ Object

Includes the module passed

Parameters:

  • inc (Module)

    the module to be mixed into the class



171
172
173
# File 'lib/orange-core/packet.rb', line 171

def self.mixin(inc)
  include inc
end

.new(orange, env) ⇒ Object

We override the instantiation to only create one packet per env

Parameters:

  • orange (Orange::Core)

    a pointer to the orange core

  • env (Hash)

    a standard Rack hash



25
26
27
28
# File 'lib/orange-core/packet.rb', line 25

def self.new(orange, env)
  return env['orange.packet'] if env['orange.packet']
  super(orange, env)
end

Instance Method Details

#[](key, default = false) ⇒ Object

Gives access to the orange.env key in the env, optionally including a default if key isn’t involved.

Parameters:

  • key (Symbol, String)

    the key to be found

  • default (optional, Object) (defaults to: false)

    the return value if key doesn’t exist (default is false)

Returns:

  • (Object)

    any value stored in the env



70
71
72
# File 'lib/orange-core/packet.rb', line 70

def [](key, default = false)
  @env['orange.env'].has_key?(key) ? @env['orange.env'][key] : default
end

#[]=(key, val) ⇒ Object

Lets user set a value in the orange.env

Parameters:

  • key (Symbol, String)

    the key to be set

  • val (Object)

    the value to be set



77
78
79
# File 'lib/orange-core/packet.rb', line 77

def []=(key, val)
  @env['orange.env'][key] = val
end

#add_header(key, val) ⇒ Object

Set a header (same as #header)

Parameters:

  • key (String)

    the key to be set

  • val (Object)

    the value to be set



124
125
126
# File 'lib/orange-core/packet.rb', line 124

def add_header(key, val)
  header key, val
end

#contentArray

Returns the content ready to be used by Rack (wrapped in an array)

Returns:

  • (Array)

    array of strings to be rendered



130
131
132
133
134
135
# File 'lib/orange-core/packet.rb', line 130

def content
  # Stringify content if it isn't a string for some weird reason.
  packet[:content] = packet[:content].to_s unless packet[:content].is_a? String
  return [packet[:content]] if packet[:content]
  return ['']
end

#envHash

Access to the main env (orange env is stored within the main env)

Returns:

  • (Hash)

    the request’s env hash



83
84
85
# File 'lib/orange-core/packet.rb', line 83

def env
  @env
end

#extract_opts(key_list = [:POST, :GET, 'route.resource_path']) ⇒ Hash

Pulls options set out of the packet and places them into a hash. Options are retrieved from POST, GET, and route.resource_path and take that order of precedence (POST overrides GET, etc)

Parameters:

  • key_list (Array) (defaults to: [:POST, :GET, 'route.resource_path'])

    an array of keys to retrieve and merge together in order of precedence. :GET and :POST for request vars, the rest are keys directly available on packet

Returns:

  • (Hash)

    A hash of options set in the packet



193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/orange-core/packet.rb', line 193

def extract_opts(key_list = [:POST, :GET, 'route.resource_path'])
  opts = {}
  key_list.reverse.each do |key|
    case key
    when :GET then opts.merge! packet.request.GET
    when :POST then opts.merge! packet.request.POST
    else 
      opts.merge!(packet[key, {}].kind_of?(String) ? url_to_hash(packet[key]) : packet[key, {}])
    end
  end
  opts
end

#finishArray

Returns the array of [status, headers, content] Rack expects

Returns:

  • (Array)

    the triple array expected by Rack at the end of a call



152
153
154
155
156
157
158
159
160
161
# File 'lib/orange-core/packet.rb', line 152

def finish
  headers = packet.headers
  status = packet[:status, 200]
  content = packet.content
  if content.respond_to?(:to_ary)
    headers["Content-Length"] = content.to_ary.
      inject(0) { |len, part| len + Rack::Utils.bytesize(part) }.to_s
  end
  [status, headers, content]
end

#flash(key = nil, val = nil) ⇒ String

Access to the rack session flash

Returns:

  • (String)

    the string stored in the flash



96
97
98
99
100
101
102
103
104
105
# File 'lib/orange-core/packet.rb', line 96

def flash(key = nil, val = nil)
  env['rack.session']["flash"] ||= {}
  if key.nil? && val.nil?
    env['rack.session']["flash"]
  elsif val.nil?
    env['rack.session']["flash"].delete(key)
  else
    env['rack.session']["flash"][key] = val
  end
end

#header(key, val) ⇒ Object

Set a header

Parameters:

  • key (String)

    the key to be set

  • val (Object)

    the value to be set



117
118
119
# File 'lib/orange-core/packet.rb', line 117

def header(key, val)
  @env['orange.env'][:headers][key] = val
end

#headersHash

Generate headers for finalization

Returns:

  • (Hash)

    the header information stored in the orange.env, combined with the defaults set as DEFAULT_HEADERS



110
111
112
# File 'lib/orange-core/packet.rb', line 110

def headers
  packet[:headers, {}].with_defaults(DEFAULT_HEADERS)
end

#matchersHash

Allows access to the matchers added via the #meta_methods method

Returns:

  • (Hash)

    the matchers hash



47
48
49
# File 'lib/orange-core/packet.rb', line 47

def matchers
  @@matchers || {}
end

#orangeOrange::Core

A pointer to the Orange::Core instance

Returns:



145
146
147
# File 'lib/orange-core/packet.rb', line 145

def orange
  @orange
end

#packetOrange::Packet

Returns self

Returns:



165
166
167
# File 'lib/orange-core/packet.rb', line 165

def packet
  self
end

#requestRack::Request

Returns the request object generated by Rack::Request(packet.env)

Returns:

  • (Rack::Request)

    the request object



139
140
141
# File 'lib/orange-core/packet.rb', line 139

def request
  packet[:request]
end

#routevoid

This method returns an undefined value.

Route calls the router object set in the packet



180
181
182
183
184
# File 'lib/orange-core/packet.rb', line 180

def route
  router = packet['route.router']
  raise 'Router not found' unless router
  router.route(self)
end

#sessionHash

Access to the rack session

Returns:

  • (Hash)

    the session information made available by Rack



89
90
91
92
# File 'lib/orange-core/packet.rb', line 89

def session
  env['rack.session']["flash"] ||= {}
  env['rack.session']
end

#url_to_hash(url) ⇒ Object

Converts a url path to a hash with symbol keys. URL must be in /key/val/key/val/etc format



208
209
210
211
212
213
214
215
216
217
218
# File 'lib/orange-core/packet.rb', line 208

def url_to_hash(url)
  parts = url.split('/')
  hash = {}
  while !parts.blank?
    key = parts.shift
    key = parts.shift if key.blank?
    val = parts.shift
    hash[key.to_sym] = val unless key.blank? or val.blank?
  end
  hash
end