manveru-innate 2009.03.24 → 2009.04

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/CHANGELOG +354 -0
  2. data/MANIFEST +34 -22
  3. data/README.md +2 -10
  4. data/Rakefile +30 -247
  5. data/example/app/retro_games.rb +8 -8
  6. data/example/app/todo/layout/{default.erb → default.xhtml} +1 -1
  7. data/example/app/todo/view/{index.erb → index.xhtml} +11 -11
  8. data/example/app/whywiki_erb/start.rb +2 -1
  9. data/example/app/whywiki_erb/view/{edit.html.erb → edit.erb} +0 -0
  10. data/example/app/whywiki_erb/view/{index.html.erb → index.erb} +0 -0
  11. data/example/howto_spec.rb +1 -1
  12. data/example/provides.rb +9 -6
  13. data/example/session.rb +3 -3
  14. data/innate.gemspec +23 -127
  15. data/lib/innate/action.rb +24 -13
  16. data/lib/innate/adapter.rb +5 -27
  17. data/lib/innate/cache/file_based.rb +2 -0
  18. data/lib/innate/cache.rb +1 -1
  19. data/lib/innate/current.rb +5 -5
  20. data/lib/innate/dynamap.rb +5 -0
  21. data/lib/innate/helper/cgi.rb +32 -19
  22. data/lib/innate/helper/link.rb +2 -2
  23. data/lib/innate/helper/redirect.rb +1 -1
  24. data/lib/innate/helper/render.rb +87 -0
  25. data/lib/innate/helper/send_file.rb +9 -1
  26. data/lib/innate/helper.rb +20 -29
  27. data/lib/innate/log/hub.rb +1 -1
  28. data/lib/innate/middleware_compiler.rb +1 -15
  29. data/lib/innate/mock.rb +2 -3
  30. data/lib/innate/node.rb +85 -55
  31. data/lib/innate/options/dsl.rb +1 -1
  32. data/lib/innate/options.rb +1 -1
  33. data/lib/innate/request.rb +3 -76
  34. data/lib/innate/response.rb +1 -8
  35. data/lib/innate/session.rb +2 -3
  36. data/lib/innate/spec.rb +6 -50
  37. data/lib/innate/version.rb +1 -1
  38. data/lib/innate/view/erb.rb +1 -5
  39. data/lib/innate/view/etanni.rb +36 -0
  40. data/lib/innate/view/none.rb +1 -1
  41. data/lib/innate/view.rb +14 -16
  42. data/lib/innate.rb +27 -53
  43. data/spec/example/app/retro_games.rb +30 -0
  44. data/spec/example/provides.rb +16 -0
  45. data/spec/example/session.rb +8 -14
  46. data/spec/innate/action/layout/file_layout.xhtml +1 -0
  47. data/spec/innate/action/layout.rb +1 -1
  48. data/spec/innate/helper/aspect.rb +6 -6
  49. data/spec/innate/helper/flash.rb +28 -47
  50. data/spec/innate/helper/link.rb +8 -0
  51. data/spec/innate/helper/redirect.rb +58 -43
  52. data/spec/innate/helper/render.rb +133 -0
  53. data/spec/innate/helper/view/aspect_hello.xhtml +1 -0
  54. data/spec/innate/helper/view/locals.xhtml +1 -0
  55. data/spec/innate/helper/view/loop.xhtml +4 -0
  56. data/spec/innate/helper/view/num.xhtml +1 -0
  57. data/spec/innate/helper/view/partial.xhtml +1 -0
  58. data/spec/innate/helper/view/recursive.xhtml +7 -0
  59. data/spec/innate/node/node.rb +5 -13
  60. data/spec/innate/node/view/another_layout/{another_layout.erb → another_layout.xhtml} +1 -1
  61. data/spec/innate/node/view/{bar.erb → bar.xhtml} +0 -0
  62. data/spec/innate/node/view/foo.html.xhtml +1 -0
  63. data/spec/innate/node/view/{only_view.erb → only_view.xhtml} +0 -0
  64. data/spec/innate/node/view/with_layout.xhtml +1 -0
  65. data/spec/innate/provides/list.html.xhtml +1 -0
  66. data/spec/innate/provides/list.txt.xhtml +1 -0
  67. data/spec/innate/provides.rb +2 -2
  68. data/spec/innate/request.rb +0 -9
  69. data/spec/innate/session.rb +14 -15
  70. data/spec/innate/state/fiber.rb +8 -7
  71. data/tasks/bacon.rake +66 -0
  72. data/tasks/changelog.rake +18 -0
  73. data/tasks/gem.rake +22 -0
  74. data/tasks/gem_installer.rake +76 -0
  75. data/tasks/grancher.rake +12 -0
  76. data/tasks/install_dependencies.rake +4 -0
  77. data/tasks/manifest.rake +4 -0
  78. data/tasks/rcov.rake +19 -0
  79. data/tasks/release.rake +51 -0
  80. data/tasks/reversion.rake +8 -0
  81. data/tasks/setup.rake +28 -0
  82. metadata +41 -38
  83. data/lib/innate/core_compatibility/basic_object.rb +0 -10
  84. data/lib/innate/core_compatibility/string.rb +0 -3
  85. data/lib/innate/helper/partial.rb +0 -93
  86. data/spec/innate/action/layout/file_layout.erb +0 -1
  87. data/spec/innate/helper/partial.rb +0 -101
  88. data/spec/innate/helper/view/aspect_hello.erb +0 -1
  89. data/spec/innate/helper/view/locals.erb +0 -1
  90. data/spec/innate/helper/view/loop.erb +0 -4
  91. data/spec/innate/helper/view/num.erb +0 -1
  92. data/spec/innate/helper/view/partial.erb +0 -1
  93. data/spec/innate/helper/view/recursive.erb +0 -8
  94. data/spec/innate/node/view/foo.html.erb +0 -1
  95. data/spec/innate/node/view/with_layout.erb +0 -1
  96. data/spec/innate/provides/list.html.erb +0 -1
  97. data/spec/innate/provides/list.txt.erb +0 -1
data/lib/innate/action.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Innate
2
- ACTION_MEMBERS = [ :node, :method, :params, :view, :layout, :instance, :exts,
3
- :wish, :options, :variables, :value, :view_value, :engine ]
2
+ ACTION_MEMBERS = [ :node, :instance, :method, :params, :method_value, :view,
3
+ :view_value, :layout, :wish, :options, :variables, :engine, :path ]
4
4
 
5
5
  class Action < Struct.new(*ACTION_MEMBERS)
6
6
  # Create a new Action instance.
@@ -32,10 +32,7 @@ module Innate
32
32
  # @api stable
33
33
  # @author manveru
34
34
  def call
35
- Current.actions << self
36
- render
37
- ensure
38
- Current.actions.delete(self)
35
+ Current.actions ? wrap_in_current{ render } : render
39
36
  end
40
37
 
41
38
  # @return [Binding] binding of the instance for this Action
@@ -100,11 +97,12 @@ module Innate
100
97
  self.variables[:content] ||= nil
101
98
 
102
99
  instance.wrap_action_call(self) do
103
- self.value = instance.__send__(method, *params) if method
104
- self.view_value = File.read(view) if view
105
- copy_variables
100
+ copy_variables # this might need another position after all
101
+ self.method_value = instance.__send__(method, *params) if method
102
+ self.view_value = ::File.read(view) if view
106
103
 
107
- body, content_type = wrap_in_layout{ engine.call(self, view_value || value) }
104
+ body, content_type = wrap_in_layout{
105
+ engine.call(self, view_value || method_value || '') }
108
106
  options[:content_type] ||= content_type if content_type
109
107
  body
110
108
  end
@@ -116,6 +114,7 @@ module Innate
116
114
  action = dup
117
115
  action.view, action.method = layout_view_or_method(*layout)
118
116
  action.layout = nil
117
+ action.view_value = nil
119
118
  action.sync_variables(self)
120
119
  body, content_type = yield
121
120
  action.variables[:content] = body
@@ -123,8 +122,14 @@ module Innate
123
122
  end
124
123
 
125
124
  def layout_view_or_method(name, arg)
126
- return arg, nil if name == :layout || name == :view
127
- return nil, arg
125
+ [:layout, :view].include?(name) ? [arg, nil] : [nil, arg]
126
+ end
127
+
128
+ def wrap_in_current
129
+ Current.actions << self
130
+ yield
131
+ ensure
132
+ Current.actions.delete(self)
128
133
  end
129
134
 
130
135
  # Try to figure out a sane name for current action.
@@ -132,8 +137,14 @@ module Innate
132
137
  File.basename((method || view).to_s).split('.').first
133
138
  end
134
139
 
140
+ # Path to this action, including params, with the mapping of the current
141
+ # controller prepended.
142
+ def full_path
143
+ File.join(node.mapping, path)
144
+ end
145
+
135
146
  def valid?
136
- method || view
147
+ node.needs_method? ? (method && view) : (method || view)
137
148
  end
138
149
  end
139
150
  end
@@ -1,23 +1,16 @@
1
- module Rack
2
- module Handler
3
- autoload :Thin, 'rack/handler/thin'
4
- autoload :Ebb, 'ebb'
5
- autoload :SwiftipliedMongrel, 'rack/handler/swiftiplied_mongrel'
6
-
7
- register 'thin', 'Rack::Handler::Thin'
8
- register 'ebb', 'Rack::Handler::Ebb'
9
- register 'smongrel', 'Rack::Handler::SwiftipliedMongrel'
10
- end
11
- end
1
+ Rack::Handler.register('ebb', 'Rack::Handler::Ebb')
12
2
 
13
3
  module Innate
14
4
 
15
5
  # Lightweight wrapper around Rack::Handler, will apply our options in a
16
6
  # unified manner and deal with adapters that don't like to do what we want or
17
7
  # where Rack doesn't want to take a stand.
8
+ #
9
+ # Rack handlers as of 2009.03.25:
10
+ # cgi, fastcgi, mongrel, emongrel, smongrel, webrick, lsws, scgi, thin
18
11
 
19
12
  module Adapter
20
- include Optional
13
+ include Optioned
21
14
 
22
15
  options.dsl do
23
16
  o "IP address or hostname that we respond to - 0.0.0.0 for all",
@@ -75,24 +68,9 @@ module Innate
75
68
 
76
69
  # Thin shouldn't give excessive output, especially not to $stdout
77
70
  def self.start_thin(app, config)
78
- require 'thin'
79
71
  handler = Rack::Handler.get('thin')
80
72
  ::Thin::Logging.silent = true
81
73
  handler.run(app, config)
82
74
  end
83
-
84
- # swiftcore has its own handler outside of rack
85
- def self.start_emongrel(app, config)
86
- require 'swiftcore/evented_mongrel'
87
- handler = Rack::Handler.get('emongrel')
88
- handler.run(app, config)
89
- end
90
-
91
- # swiftcore has its own handler outside of rack
92
- def self.start_smongrel(app, config)
93
- require 'swiftcore/swiftiplied_mongrel'
94
- handler = Rack::Handler.get('smongrel')
95
- handler.run(app, config)
96
- end
97
75
  end
98
76
  end
@@ -3,6 +3,8 @@ module Innate
3
3
 
4
4
  # Used by caches that serialize their contents to the filesystem.
5
5
  module FileBased
6
+ attr_reader :filename
7
+
6
8
  def cache_setup(*args)
7
9
  @prefix = args.compact.join('-')
8
10
 
data/lib/innate/cache.rb CHANGED
@@ -61,7 +61,7 @@ module Innate
61
61
  autoload :Marshal, 'innate/cache/marshal'
62
62
  autoload :FileBased, 'innate/cache/file_based'
63
63
 
64
- include Optional
64
+ include Optioned
65
65
 
66
66
  options.dsl do
67
67
  o "Assign a cache to each of these names on Innate::Cache::setup",
@@ -25,11 +25,11 @@ module Innate
25
25
  end
26
26
  end
27
27
 
28
- # Setup new Request/Response/Session for this request/response cycle
29
-
30
- def setup(env)
31
- req = STATE[:request] = Request.new(env)
32
- res = STATE[:response] = Response.new
28
+ # Setup new Request/Response/Session for this request/response cycle.
29
+ # The parameters are here to allow Ramaze to inject its own classes.
30
+ def setup(env, request = Request, response = Response, session = Session)
31
+ req = STATE[:request] = request.new(env)
32
+ res = STATE[:response] = response.new
33
33
  STATE[:actions] = []
34
34
  STATE[:session] = Session.new(req, res)
35
35
  end
@@ -18,6 +18,11 @@ module Innate
18
18
  remap(@originals.merge(location.to_s => object))
19
19
  end
20
20
 
21
+ def delete(location)
22
+ @originals.delete(location)
23
+ remap(@originals)
24
+ end
25
+
21
26
  def at(location)
22
27
  @originals[location]
23
28
  end
@@ -6,36 +6,49 @@ module Innate
6
6
 
7
7
  module Helper
8
8
  module CGI
9
- # shortcut for Rack::Utils.escape
10
- def url_encode(*args)
11
- Rack::Utils.escape(*args.map{|a| a.to_s })
9
+ module_function
10
+
11
+ # Shortcut for Rack::Utils.escape
12
+ #
13
+ # @param [#to_s] input
14
+ # @return [String] URI-encoded representation of +input+
15
+ def url_encode(input)
16
+ Rack::Utils.escape(input.to_s)
12
17
  end
18
+ alias u url_encode
13
19
 
14
- # shortcut for Rack::Utils.unescape
15
- def url_decode(*args)
16
- Rack::Utils.unescape(*args.map{|a| a.to_s })
20
+ # Shortcut for Rack::Utils.unescape
21
+ #
22
+ # @param [#to_s] input
23
+ # @return [String] URI-decoded representation of +input+
24
+ def url_decode(input)
25
+ Rack::Utils.unescape(input.to_s)
17
26
  end
18
27
 
19
- # shortcut for Rack::Utils.escape_html
20
- def html_escape(string)
21
- Rack::Utils.escape_html(string)
28
+ # Shortcut for Rack::Utils.escape_html
29
+ #
30
+ # @param [#to_s] input
31
+ # @return [String]
32
+ def html_escape(input)
33
+ Rack::Utils.escape_html(input.to_s)
22
34
  end
23
35
 
24
- # shortcut for CGI.unescapeHTML
25
- def html_unescape(string)
26
- ::CGI.unescapeHTML(string.to_s)
36
+ # Shortcut for CGI.unescapeHTML
37
+ #
38
+ # @param [#to_s] input
39
+ # @return [String]
40
+ def html_unescape(input)
41
+ ::CGI.unescapeHTML(input.to_s)
27
42
  end
28
43
 
29
44
  # safely escape all HTML and code
30
- def h(string)
31
- Rack::Utils.escape_html(string).gsub(/#([{@$]@?)/, '&#35;\1')
45
+ def html_and_code_escape(input)
46
+ Rack::Utils.escape_html(input.to_s).gsub(/#([{@$]@?)/, '&#35;\1')
32
47
  end
48
+ alias h html_and_code_escape
33
49
 
34
- # one-letter versions help in case like #{h foo.inspect}
35
- # ERb/ERuby/Rails compatible
36
- alias u url_encode
37
-
38
- module_function(:url_encode, :url_decode, :html_escape, :html_unescape, :h, :u)
50
+ # aliases are ignored by module_function...
51
+ module_function :u, :h
39
52
  end
40
53
  end
41
54
  end
@@ -28,12 +28,12 @@ module Innate
28
28
  hashes, names = args.partition{|arg| arg.respond_to?(:merge!) }
29
29
  hashes.each{|to_merge| hash.merge!(to_merge) }
30
30
 
31
+ escape = Rack::Utils.method(:escape)
31
32
  location = route_location(self)
32
- front = Array[location, name, *names].join('/').squeeze('/')
33
+ front = Array[location, name, *names.map{|n| escape[n]}].join('/').squeeze('/')
33
34
 
34
35
  return URI(front) if hash.empty?
35
36
 
36
- escape = Rack::Utils.method(:escape)
37
37
  query = hash.map{|k, v| "#{escape[k]}=#{escape[v]}" }.join(';')
38
38
  URI("#{front}?#{query}")
39
39
  end
@@ -57,7 +57,7 @@ module Innate
57
57
  end
58
58
 
59
59
  def raw_redirect(target, options = {}, &block)
60
- header = {'Location' => target.to_s}
60
+ header = response.header.merge('Location' => target.to_s)
61
61
  status = options[:status] || 302
62
62
  body = options[:body] || redirect_body(target)
63
63
 
@@ -0,0 +1,87 @@
1
+ module Innate
2
+ module Helper
3
+ module Render
4
+ # Enables you to simply call:
5
+ #
6
+ # @example of added functionality
7
+ # YourController.render_partial(:foo, :x => 42)
8
+ #
9
+ def self.included(into)
10
+ into.extend(self)
11
+ end
12
+
13
+ # Renders the full action in the way a real request would.
14
+ #
15
+ # Please be aware that, if this is the first request from a client, you
16
+ # will not have access to the session in the action being rendered, as no
17
+ # actual session has been put into place yet.
18
+ #
19
+ # It should work as expected on any subsequent requests.
20
+ #
21
+ # As usual, patches welcome.
22
+ #
23
+ # @api external
24
+ # @see Mock.session
25
+ # @author manveru
26
+ def render_full(path, query = {})
27
+ uri = URI(path.to_s)
28
+ uri.query = Rack::Utils.build_query(query)
29
+
30
+ if cookie = request.env['HTTP_COOKIE']
31
+ Mock.session do |mock|
32
+ mock.cookie = cookie
33
+ return mock.get(uri.to_s).body
34
+ end
35
+ else
36
+ Mock.get(uri.to_s).body
37
+ end
38
+ end
39
+
40
+ # Renders an action without any layout.
41
+ # You can further tweak the action to be rendered by passing a block.
42
+ #
43
+ # @api external
44
+ # @see render_custom
45
+ # @author manveru
46
+ def render_partial(action_name, variables = {})
47
+ render_custom(action_name, variables) do |action|
48
+ action.layout = nil
49
+ yield(action) if block_given?
50
+ end
51
+ end
52
+
53
+ # Renders an action view, doesn't execute any methods and won't wrap it
54
+ # into a layout.
55
+ # You can further tweak the action to be rendered by passing a block.
56
+ #
57
+ # @api external
58
+ # @see render_custom
59
+ # @author manveru
60
+ def render_view(action_name, variables = {})
61
+ render_custom(action_name, variables) do |action|
62
+ action.layout = nil
63
+ action.method = nil
64
+ yield(action) if block_given?
65
+ end
66
+ end
67
+
68
+ def render_custom(action_name, variables = {})
69
+ unless action = resolve(action_name.to_s)
70
+ raise(ArgumentError, "No Action %p on #{self}" % action_name)
71
+ end
72
+
73
+ action.sync_variables(self.action)
74
+ action.instance = action.node.new
75
+ action.variables = action.variables.merge(variables)
76
+
77
+ yield(action) if block_given?
78
+
79
+ if action.valid?
80
+ action.render
81
+ else
82
+ Log.warn("Invalid action: %p" % action)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -3,12 +3,20 @@ module Innate
3
3
  module SendFile
4
4
  # Not optimally performing but convenient way to send files by their
5
5
  # filename.
6
- def send_file(filename, content_type = nil)
6
+ #
7
+ # I think we should remove this from the default helpers and move it into
8
+ # Ramaze, the functionality is almost never used, the naming is ambigous,
9
+ # and it doesn't use the send_file capabilities of frontend servers.
10
+ #
11
+ # So for now, I'll mark it for deprecation
12
+ def send_file(filename, content_type = nil, content_disposition = nil)
7
13
  content_type ||= Rack::Mime.mime_type(::File.extname(filename))
14
+ content_disposition ||= File.basename(filename)
8
15
 
9
16
  response.body = ::File.readlines(filename, 'rb')
10
17
  response['Content-Length'] = ::File.size(filename).to_s
11
18
  response['Content-Type'] = content_type
19
+ response['Content-Disposition'] = content_disposition
12
20
  response.status = 200
13
21
 
14
22
  throw(:respond, response)
data/lib/innate/helper.rb CHANGED
@@ -11,6 +11,7 @@ module Innate
11
11
  def self.included(into)
12
12
  into.extend(HelperAccess)
13
13
  into.__send__(:include, Trinity)
14
+ into.helper(*HelpersHelper.options[:default])
14
15
  end
15
16
  end
16
17
 
@@ -63,34 +64,27 @@ module Innate
63
64
  #
64
65
  # p Innate::HelpersHelper.each(:cgi, :link, :aspect)
65
66
  module HelpersHelper
66
- EXTS = %w[rb so bundle]
67
+ include Optioned
67
68
 
68
- # By default, lib/innate/ is added to the PATH, you may add your
69
- # application root here so innate will look in your own helper/ directory.
70
- PATH = []
69
+ options.dsl do
70
+ o "Paths that will be searched for helper files",
71
+ :paths, [Dir.pwd, File.dirname(__FILE__)]
71
72
 
72
- # The namespaces that may container helper modules.
73
- # Lookup is done from left to right.
74
- POOL = []
73
+ o "Namespaces that will be searched for helper modules",
74
+ :namespaces, [Helper]
75
75
 
76
- # all of the following are singleton methods
76
+ o "Filename extensions considered for helper files",
77
+ :exts, %w[rb so bundle]
77
78
 
78
- module_function
79
-
80
- def add_pool(pool)
81
- POOL.unshift(pool)
82
- POOL.uniq!
79
+ o "Default helpers, added on inclusion of the Helper module",
80
+ :default, [:aspect, :cgi, :flash, :link, :render, :redirect, :send_file]
83
81
  end
84
82
 
85
- add_pool(Helper)
83
+ EXTS = %w[rb so bundle]
86
84
 
87
- def add_path(path)
88
- PATH.unshift(File.expand_path(path))
89
- PATH.uniq!
90
- end
85
+ # all of the following are singleton methods
91
86
 
92
- add_path(File.dirname(__FILE__))
93
- add_path('')
87
+ module_function
94
88
 
95
89
  # Yield all the modules we can find for the given names of helpers, try to
96
90
  # require them if not available.
@@ -158,10 +152,10 @@ module Innate
158
152
  # helper :foo_bar # => FooBar
159
153
  # helper :foo # => Foo
160
154
  def get(name)
161
- name = name.to_s.split('_').map{|e| e.capitalize}.join
155
+ module_name = /^#{name.to_s.dup.delete('_')}$/i
162
156
 
163
- POOL.each do |namespace|
164
- found = namespace.constants.grep(/^#{name}$/i).first
157
+ options.namespaces.each do |namespace|
158
+ found = namespace.constants.grep(module_name).first
165
159
  return namespace.const_get(found) if found
166
160
  end
167
161
 
@@ -181,12 +175,9 @@ module Innate
181
175
  # Return a nice list of filenames in correct locations with correct
182
176
  # filename-extensions.
183
177
  def glob(name = '*')
184
- "{#{paths.join(',')}}/helper/#{name}.{#{EXTS.join(',')}}"
185
- end
186
-
187
- # In case you want to do something better.
188
- def paths
189
- PATH
178
+ exts, paths = options.exts, options.paths
179
+ paths.uniq!
180
+ "{#{paths.join(',')}}/helper/#{name}.{#{exts.join(',')}}"
190
181
  end
191
182
  end
192
183
  end
@@ -38,7 +38,7 @@ module Innate
38
38
 
39
39
  class LogHub
40
40
  include Logger::Severity
41
- include Optional
41
+ include Optioned
42
42
 
43
43
  attr_accessor :loggers, :program, :active
44
44
 
@@ -47,27 +47,13 @@ module Innate
47
47
  cascade(*apps)
48
48
  end
49
49
 
50
- def static(path)
51
- require 'rack/contrib'
52
- Rack::ETag.new(Rack::ConditionalGet.new(Rack::File.new(path)))
53
- end
54
-
55
- def directory(path)
56
- require 'rack/contrib'
57
- Rack::ETag.new(Rack::ConditionalGet.new(Rack::Directory.new(path)))
58
- end
59
-
60
50
  def call(env)
61
51
  compile
62
52
  @compiled.call(env)
63
53
  end
64
54
 
65
- def compiled?
66
- @compiled
67
- end
68
-
69
55
  def compile
70
- compiled? ? self : compile!
56
+ @compiled ? self : compile!
71
57
  end
72
58
 
73
59
  def compile!
data/lib/innate/mock.rb CHANGED
@@ -39,9 +39,8 @@ module Innate
39
39
  hash['HTTP_COOKIE'] ||= @cookie if @cookie
40
40
  response = Mock::mock(method, path, hash)
41
41
 
42
- if cookie = response['Set-Cookie']
43
- @cookie = cookie
44
- end
42
+ cookie = response['Set-Cookie']
43
+ @cookie = cookie if cookie
45
44
 
46
45
  response
47
46
  end