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.



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.

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



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



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.



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



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)



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)



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)



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)



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



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



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



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



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



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

def matchers
  @@matchers || {}
end

#orangeOrange::Core

A pointer to the Orange::Core instance



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

def orange
  @orange
end

#packetOrange::Packet

Returns self



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)



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



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