bluepotion 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/lib/project/blue_potion_net.rb +105 -0
  3. data/lib/project/ext/object.rb +2 -0
  4. data/lib/project/potion.rb +19 -3
  5. data/lib/project/potion_dialog/potion_dialog.rb +46 -0
  6. data/lib/project/pro_motion/{pm_activity.rb → activities/pm_activity.rb} +18 -0
  7. data/lib/project/pro_motion/activities/pm_home_activity.rb +14 -0
  8. data/lib/project/pro_motion/activities/pm_navigation_activity.rb +83 -0
  9. data/lib/project/pro_motion/{pm_single_fragment_activity.rb → activities/pm_single_fragment_activity.rb} +14 -3
  10. data/lib/project/pro_motion/adapters/pm_base_adapter.rb +75 -0
  11. data/lib/project/pro_motion/adapters/pm_cursor_adapter.rb +44 -0
  12. data/lib/project/pro_motion/fragments/pm_list_screen.rb +191 -0
  13. data/lib/project/pro_motion/{pm_screen.rb → fragments/pm_screen.rb} +31 -6
  14. data/lib/project/pro_motion/{pm_screen_module.rb → fragments/pm_screen_module.rb} +72 -20
  15. data/lib/project/pro_motion/pm_application.rb +15 -4
  16. data/lib/project/pro_motion/{pm_hash_bundle.rb → support/pm_hash_bundle.rb} +4 -0
  17. data/lib/project/ruby_motion_query/rmq/base.rb +1 -1
  18. data/lib/project/ruby_motion_query/rmq/data.rb +2 -36
  19. data/lib/project/ruby_motion_query/rmq/subviews.rb +30 -0
  20. data/lib/project/ruby_motion_query/rmq_color.rb +1 -1
  21. data/lib/project/ruby_motion_query/rmq_resource.rb +26 -0
  22. data/lib/project/version.rb +1 -1
  23. data/lib/project/volley_wrap/http_result.rb +98 -0
  24. data/lib/project/volley_wrap/request.rb +98 -0
  25. data/lib/project/volley_wrap/response_listener.rb +49 -0
  26. data/lib/project/volley_wrap/session_client.rb +72 -0
  27. metadata +19 -8
  28. data/lib/project/pro_motion/pm_home_activity.rb +0 -16
@@ -6,7 +6,11 @@
6
6
 
7
7
  attr_accessor :view
8
8
 
9
- def onAttach(activity); super; on_attach(activity); end
9
+ def onAttach(activity)
10
+ super
11
+ activity.on_fragment_attached(self) if activity.respond_to?(:on_fragment_attached)
12
+ on_attach(activity)
13
+ end
10
14
  def on_attach(activity); end
11
15
 
12
16
  def onCreate(bundle); super; on_create(bundle); end
@@ -18,7 +22,8 @@
18
22
  if @xml_resource = self.class.xml_resource
19
23
  @view = inflater.inflate(r(:layout, @xml_resource), parent, false)
20
24
  else
21
- @view = load_view
25
+ v = load_view
26
+ @view ||= v
22
27
  @view.setId Potion::ViewIdGenerator.generate
23
28
  end
24
29
 
@@ -50,9 +55,7 @@
50
55
 
51
56
  build_and_tag_xml_views
52
57
 
53
- self.action_bar.title = self.class.bars_title
54
- self.activity.title = self.class.bars_title
55
-
58
+ set_title
56
59
  on_load
57
60
  on_activity_created
58
61
  end
@@ -80,9 +83,31 @@
80
83
  def onDestroy; super; on_destroy; end
81
84
  def on_destroy; end
82
85
 
83
- def onDetach; super; on_detach; end
86
+ def onDetach
87
+ super
88
+ on_detach
89
+ self.activity.on_fragment_detached(self) if self.activity.respond_to?(:on_fragment_detached)
90
+ end
84
91
  def on_detach; end
85
92
 
93
+ def set_title
94
+ self.title = self.class.bars_title
95
+ end
96
+
97
+ def title
98
+ @title
99
+ end
100
+ def title=(value)
101
+ @title = value
102
+
103
+ if a = self.activity
104
+ if a_bar = self.action_bar
105
+ a_bar.title = value
106
+ end
107
+ a.title = value
108
+ end
109
+ end
110
+
86
111
  private
87
112
 
88
113
  def build_and_tag_xml_views
@@ -93,8 +93,21 @@
93
93
  self.rmq.append(view_or_class, style, opts).get
94
94
  end
95
95
 
96
- # TODO add create and build
96
+ def create(view_or_class, style=nil, opts={})
97
+ self.rmq.create(view_or_class, style, opts)
98
+ end
99
+
100
+ def create!(view_or_class, style=nil, opts={})
101
+ self.rmq.create(view_or_class, style, opts).get
102
+ end
97
103
 
104
+ def build(view_or_class, style=nil, opts={})
105
+ self.rmq.build(view_or_class, style, opts)
106
+ end
107
+
108
+ def build!(view_or_class, style=nil, opts={})
109
+ self.rmq.build(view_or_class, style, opts).get
110
+ end
98
111
 
99
112
  # temporary stand-in for Java's R class
100
113
  def r(resource_type, resource_name)
@@ -108,15 +121,27 @@
108
121
 
109
122
  def open(screen_class, options={})
110
123
  mp "ScreenModule open", debugging_only: true
111
- activity_class = options.delete(:activity) || PMSingleFragmentActivity
112
124
 
113
- # TODO: replace the fragment in the activity when possible
114
- # replace the fragment if we can; otherwise launch a new activity
115
- # we're taking a conservative approach for now - eventually we'll want to allow
116
- # replacing fragments for any kind of activity, but I'm not sure of the best way
117
- # to implement that yet
118
- intent = Android::Content::Intent.new(self.activity, activity_class)
119
- intent.putExtra PMSingleFragmentActivity::EXTRA_FRAGMENT_CLASS, screen_class.to_s
125
+ if !options[:activity] && self.activity.respond_to?(:open_fragment)
126
+ if screen_class.respond_to?(:new)
127
+ screen = screen_class.new
128
+ else
129
+ screen = screen_class
130
+ end
131
+ self.activity.open_fragment screen, options
132
+ else
133
+ open_modal(screen_class, options)
134
+ end
135
+ end
136
+
137
+ def open_modal(screen_class, options)
138
+ activity_class = options.delete(:activity) || PMNavigationActivity
139
+ activity_class = PMNavigationActivity if activity_class == :nav
140
+ activity_class = PMSingleFragmentActivity if activity_class == :single
141
+
142
+ intent = Potion::Intent.new(self.activity, activity_class)
143
+ intent.putExtra PMActivity::EXTRA_FRAGMENT_CLASS, screen_class.to_s
144
+ intent.setFlags(Potion::Intent::FLAG_ACTIVITY_CLEAR_TOP) if options.delete(:close)
120
145
 
121
146
  if extras = options.delete(:extras)
122
147
  extras.keys.each do |key, value|
@@ -128,18 +153,34 @@
128
153
  unless options.blank?
129
154
  # The rest of the options are screen accessors, we use fragment arguments for this
130
155
  hash_bundle = PMHashBundle.from_hash(options)
131
- intent.putExtra PMSingleFragmentActivity::EXTRA_FRAGMENT_ARGUMENTS, hash_bundle.to_bundle
156
+ intent.putExtra PMActivity::EXTRA_FRAGMENT_ARGUMENTS, hash_bundle.to_bundle
132
157
  end
133
158
 
134
159
  self.activity.startActivity intent
135
160
  end
136
161
 
137
162
  def close(options={})
138
- self.activity.finish
163
+ # Hang onto an activity reference, since we lose the activity
164
+ act = self.activity
165
+
166
+ if options[:activity] && options[:to_screen]
167
+ # Closing to particular activity
168
+ open options[:to_screen], activity: options[:activity], close: true
169
+ elsif options[:to_screen]
170
+ # Closing to particular fragment
171
+ while act.fragment && !act.fragment.is_a?(options[:to_screen])
172
+ act.close_fragment
173
+ act.finish unless act.fragment
174
+ end
175
+ else
176
+ # Closing current screen or activity if no screens left
177
+ act.close_fragment if act.fragment
178
+ act.finish unless act.fragment
179
+ end
139
180
  end
140
181
 
141
182
  def start_activity(activity_class)
142
- intent = Android::Content::Intent.new(self.activity, activity_class)
183
+ intent = Potion::Intent.new(self.activity, activity_class)
143
184
  #intent.putExtra("key", value); # Optional parameters
144
185
  self.activity.startActivity(intent)
145
186
  end
@@ -158,13 +199,10 @@
158
199
  input_manager.hideSoftInputFromWindow(view.getWindowToken(), 0);
159
200
  end
160
201
 
161
-
162
- def activity
163
- getActivity()
164
- end
165
-
166
202
  def action_bar
167
- activity.getActionBar()
203
+ if a = activity
204
+ a.getActionBar
205
+ end
168
206
  end
169
207
 
170
208
  def menu
@@ -173,6 +211,7 @@
173
211
 
174
212
  # Example: add_action_bar_button(title: "My text", show: :if_room)
175
213
  def add_action_bar_button(options={})
214
+ @action_bar ||= { button_actions: {} }
176
215
  unless menu
177
216
  mp "#{self.inspect}#add_action_bar_button: No menu set up yet."
178
217
  return
@@ -187,11 +226,24 @@
187
226
  show_as_action = 4 if options[:show] == :with_text
188
227
  show_as_action = 8 if options[:show] == :collapse
189
228
 
190
- btn = self.activity.menu.add(options.fetch(:group, 0), options.fetch(:item_id, 0), options.fetch(:order, 0), options.fetch(:title, "Untitled"))
229
+ btn = self.activity.menu.add(options.fetch(:group, 0), options.fetch(:item_id, @action_bar[:current_id] || 0), options.fetch(:order, 0), options.fetch(:title, ""))
191
230
  btn.setShowAsAction(show_as_action) if show_as_action
192
- btn.setIcon(options[:icon]) if options[:icon]
231
+ btn.setIcon(image.resource(options[:icon].to_s)) if options[:icon]
232
+ @action_bar[:button_actions][btn.getItemId] = options[:action] if options[:action]
233
+ @action_bar[:current_id] = btn.getItemId + 1
193
234
  btn
194
235
  end
195
236
 
237
+ def on_options_item_selected(item)
238
+ return unless @action_bar
239
+ return unless method_name = @action_bar[:button_actions][item.getItemId]
240
+ if respond_to?(method_name)
241
+ send(method_name)
242
+ else
243
+ mp "#{self.inspect} No method #{method_name.inspect} implemented for this screen."
244
+ true
245
+ end
246
+ end
247
+
196
248
  end
197
249
  #end
@@ -43,11 +43,10 @@
43
43
  end
44
44
  end
45
45
 
46
+ # Typically you don't use this, use `find.screen` instead, TODO, probably should remove this
46
47
  def current_screen
47
- if @current_activity && (ca = @current_activity)
48
- if ca.is_a?(PMSingleFragmentActivity)
49
- ca.fragment
50
- end
48
+ if @current_activity && @current_activity.respond_to?(:fragment)
49
+ @current_activity.fragment
51
50
  end
52
51
  end
53
52
 
@@ -78,6 +77,18 @@
78
77
  environment == :development
79
78
  end
80
79
 
80
+ def resource
81
+ RMQResource
82
+ end
83
+
84
+ def net
85
+ BluePotionNet
86
+ end
87
+
88
+ def async(options={}, &block)
89
+ MotionAsync.async(options, &block)
90
+ end
91
+
81
92
  class << self
82
93
  attr_accessor :current_application, :home_screen_class
83
94
 
@@ -30,6 +30,8 @@ class PMHashBundle
30
30
  value = case value_type
31
31
  when "com.rubymotion.String"
32
32
  bundle.getString(key)
33
+ when "com.rubymotion.Symbol"
34
+ bundle.getString(key).to_sym
33
35
  when "java.lang.Integer"
34
36
  bundle.getInt(key)
35
37
  when "java.lang.Double"
@@ -64,6 +66,8 @@ class PMHashBundle
64
66
  case value_type
65
67
  when "com.rubymotion.String"
66
68
  bundle.putString(key, value)
69
+ when "com.rubymotion.Symbol"
70
+ bundle.putString(key, value.to_s)
67
71
  when "java.lang.Integer"
68
72
  bundle.putInt(key, value)
69
73
  when "java.lang.Double"
@@ -8,7 +8,7 @@ class RMQ
8
8
  if value.is_a?(Potion::Activity)
9
9
  @originated_from = value
10
10
  @activity = value
11
- elsif value.is_a?(PMScreen)
11
+ elsif value.is_a?(PMScreen) || value.is_a?(PMListScreen)
12
12
  @originated_from = value
13
13
  elsif value.is_a?(Potion::View)
14
14
  @originated_from = value
@@ -3,25 +3,8 @@ class RMQ
3
3
  if new_data != :rmq_not_provided
4
4
  selected.each do |view|
5
5
  case view
6
- #when UILabel then view.setText new_data # set is faster than =
7
- #when UIButton then view.setTitle(new_data, forState: UIControlStateNormal)
8
- #when UIImageView then view.image = new_data
9
- #when UITableView then
10
- #when UISwitch then view.setOn(new_data)
11
- #when UIDatePicker then
12
- #when UISegmentedControl then
13
- #when UIRefreshControl then
14
- #when UIPageControl then
15
- #when UISlider then
16
- #when UIStepper then
17
- #when UITabBar then
18
- #when UITableViewCell then
6
+ when Potion::EditText then view.text = new_data.to_s.toString
19
7
  when Potion::TextView then view.text = new_data
20
- #when UITextField then view.text = new_data
21
- #when UINavigationBar then
22
- #when UIScrollView then
23
- #when UIProgressView then view.setProgress(new_data, animated: true)
24
-
25
8
  # TODO, finish
26
9
  end
27
10
  end
@@ -30,25 +13,8 @@ class RMQ
30
13
  else
31
14
  out = selected.map do |view|
32
15
  case view
33
- #when UILabel then view.text
34
- #when UIButton then view.titleForState(UIControlStateNormal)
35
- #when UIImageView then view.image
36
- #when UITableView then
37
- #when UISwitch then
38
- #when UIDatePicker then
39
- #when UISegmentedControl then
40
- #when UIRefreshControl then
41
- #when UIPageControl then
42
- #when UISlider then
43
- #when UIStepper then
44
- #when UITabBar then
45
- #when UITableViewCell then
16
+ when Potion::EditText then view.text.toString.to_s
46
17
  when Potion::TextView then view.text
47
- #when UITextField then view.text
48
- #when UINavigationBar then
49
- #when UIScrollView then
50
- #when UIProgressView then view.progress
51
-
52
18
  # TODO, finish
53
19
  end
54
20
  end
@@ -6,9 +6,17 @@ class RMQ
6
6
  created = false
7
7
  appended = false
8
8
  built = false
9
+ tag_xml_layout = false
9
10
 
10
11
  if view_or_class.is_a?(Potion::View)
11
12
  new_view = view_or_class
13
+ elsif view_or_class.is_a?(Symbol) # Inflate from xml
14
+ created = true
15
+ layout = RMQResource.layout(view_or_class)
16
+
17
+ inflater = Potion::LayoutInflater.from(self.activity)
18
+ new_view = inflater.inflate(layout, nil)
19
+ tag_xml_layout = true
12
20
  else
13
21
  created = true
14
22
  new_view = view_or_class.new(RMQ.app.context)
@@ -48,6 +56,8 @@ class RMQ
48
56
  if self.stylesheet
49
57
  apply_style_to_view(new_view, opts[:style]) if opts[:style]
50
58
  end
59
+
60
+ tag_all_from_resource_entry_name(new_view) if tag_xml_layout
51
61
  end
52
62
 
53
63
  viewq = RMQ.create_with_array_and_selectors(subviews_added, selectors, @originated_from, self)
@@ -57,6 +67,26 @@ class RMQ
57
67
  end
58
68
  alias :insert :add_subview
59
69
 
70
+ def tag_all_from_resource_entry_name(view)
71
+ view.rmq.find.each do |view|
72
+ if ren = view.resource_entry_name
73
+ view.rmq_data.tag(ren.to_sym)
74
+ end
75
+ end
76
+ end
77
+
78
+
79
+ # Removes the selected views from their parent's (superview) subview array
80
+ #
81
+ # @example
82
+ # rmq(a_view, another_view).remove
83
+ #
84
+ # @return [RMQ]
85
+ def remove
86
+ selected.each { |view| view.parent.removeView(view) }
87
+ self
88
+ end
89
+
60
90
  def append(view_or_class, style=nil, opts={}, dummy=nil) # <- dummy is to get around RM bug)
61
91
  opts[:style] = style
62
92
  #opts[:block] = block if block
@@ -92,7 +92,7 @@ end
92
92
  class RMQColorFactory
93
93
 
94
94
  class << self
95
- def build(params)
95
+ def build(params, dummy=nil) # Dummy works around RM bug
96
96
  return RMQColor if params.empty?
97
97
  return from_rgba(*params) if params.count > 1
98
98
 
@@ -0,0 +1,26 @@
1
+ class RMQ
2
+ # @return [RMQResource]
3
+ def self.resource
4
+ RMQResource
5
+ end
6
+
7
+ # @return [RMQResource]
8
+ def resource
9
+ RMQResource
10
+ end
11
+ end
12
+
13
+ class RMQResource
14
+ class << self
15
+ def find(resource_type, resource_name)
16
+ application = PMApplication.current_application
17
+ application.resources.getIdentifier(resource_name.to_s,
18
+ resource_type.to_s,
19
+ application.package_name)
20
+ end
21
+
22
+ def layout(name)
23
+ self.find("layout", name)
24
+ end
25
+ end
26
+ end
@@ -1,3 +1,3 @@
1
1
  module BluePotion
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -0,0 +1,98 @@
1
+ module VW
2
+ class HTTPResult
3
+ attr_accessor :object, :error, :response, :request_url, :request_params, :request_method
4
+
5
+ def initialize(response, response_object, error)
6
+ @response = response
7
+ @object = response_object
8
+ @error = error
9
+ end
10
+
11
+ def status_code
12
+ @response.statusCode if @response
13
+ end
14
+
15
+ def not_modified?
16
+ @response.notModified if @response
17
+ end
18
+
19
+ def body
20
+ @object.to_s if @object
21
+ end
22
+
23
+ def method_description
24
+ case @request_method
25
+ when 0
26
+ "GET"
27
+ when 1
28
+ "POST"
29
+ when 2
30
+ "PUT"
31
+ when 3
32
+ "DELETE"
33
+ else
34
+ "Unknown"
35
+ end
36
+ end
37
+
38
+ def headers
39
+ if @response
40
+ @_headers ||= @response.headers.inject({}){|h, entry_set| h[entry_set[0]] = entry_set[1] ; h }
41
+ end
42
+ end
43
+
44
+ def success?
45
+ !failure?
46
+ end
47
+
48
+ def failure?
49
+ !!error
50
+ end
51
+
52
+ def inspect
53
+ "<VW::HTTPResult:#{self.object_id} #{@request_url}>"
54
+ end
55
+
56
+ def to_s
57
+ header_string = if (h = headers)
58
+ h.map{|k,v| " #{k} = #{v}"}.join("\n")
59
+ else
60
+ "none"
61
+ end
62
+
63
+ #mp @request_params.class.name
64
+ params_string = if @request_params
65
+ #@request_params.class.name
66
+ @request_params.map{|k,v| " #{k} = #{v}"}.join("\n")
67
+ else
68
+ "none"
69
+ end
70
+
71
+ %(
72
+
73
+ Request -------------------------
74
+
75
+ URL: #{@request_url}
76
+ Method: #{method_description}
77
+ Params:
78
+ #{params_string}
79
+
80
+ Response -------------------------
81
+
82
+ Status code: #{status_code}
83
+ Not modified?: #{not_modified?}
84
+ Success: #{success?}
85
+
86
+ Error: #{error.toString if error}
87
+
88
+ Headers:
89
+ #{header_string}
90
+
91
+ Body:
92
+ #{body}
93
+ \n
94
+ )
95
+ end
96
+ end
97
+ end
98
+
@@ -0,0 +1,98 @@
1
+ module VW
2
+ class Request < Com::Android::Volley::Toolbox::StringRequest
3
+ # part of this class had to be implemented as a Java extension to work around
4
+ # what appears to be a RM bug. See request.java
5
+
6
+ VOLLEY_GET = 0
7
+ VOLLEY_POST = 1
8
+ VOLLEY_PUT = 2
9
+ VOLLEY_DELETE = 3
10
+
11
+ def self.get_request(url, listener)
12
+ set_request_for_listener VOLLEY_GET, url, nil, listener
13
+ Request.new(VOLLEY_GET, url, listener, listener).tap do |req|
14
+ req.setRetryPolicy(retry_policy)
15
+ req.listener = listener
16
+ end
17
+ end
18
+
19
+ def self.post_request(url, params, listener)
20
+ request_with_params(VOLLEY_POST, url, params, listener).tap do |req|
21
+ req.listener = listener
22
+ end
23
+ end
24
+
25
+ def self.put_request(url, params, listener)
26
+ request_with_params(VOLLEY_PUT, url, params, listener).tap do |req|
27
+ req.listener = listener
28
+ end
29
+ end
30
+
31
+ def self.delete_request(url, params, listener)
32
+ request_with_params(VOLLEY_DELETE, url, params, listener).tap do |req|
33
+ req.listener = listener
34
+ end
35
+ end
36
+
37
+ def listener=(value)
38
+ @listener = value
39
+ end
40
+
41
+ def self.retry_policy
42
+ Com::Android::Volley::DefaultRetryPolicy.new(10000, 3, 1)
43
+ end
44
+
45
+ def headers=(headers)
46
+ # call into the method defined in the .java file
47
+ setHeaders(headers)
48
+ end
49
+
50
+ def parseNetworkResponse(network_response)
51
+ @listener.network_response = network_response if @listener
52
+ super
53
+ end
54
+
55
+ def self.set_request_for_listener(method, url, params, listener)
56
+ # There probably is a much better way then passing all these around like this
57
+ listener.request_url = url
58
+ listener.request_params = params
59
+ listener.request_method = method
60
+ end
61
+
62
+ private
63
+
64
+ # this is to maintain compatibility with AFMotion - somewhere (possibly in AFNetworking?) the
65
+ # keys get flattened out like so:
66
+ #
67
+ # { user: { email: "x@x.com", password: "pass" } }
68
+ # becomes
69
+ # { "user[email]" => "x@x.com", "user[password]" => "pass" }
70
+ #
71
+ # This is not a robust implementation of this, but will serve our needs for now
72
+ def self.prepare_params(params)
73
+ new_params = {}
74
+ params.keys.each do |key|
75
+ if params[key].is_a?(Hash)
76
+ params[key].keys.each do |inner_key|
77
+ new_params["#{key}[#{inner_key}]"] = params[key][inner_key].to_s
78
+ end
79
+ else
80
+ new_params[key.to_s] = params[key].to_s
81
+ end
82
+ end
83
+ new_params
84
+ end
85
+
86
+ def self.request_with_params(method, url, params, listener)
87
+ set_request_for_listener method, url, params, listener
88
+
89
+ Request.new(method, url, listener, listener).tap do |req|
90
+ req.setRetryPolicy(retry_policy)
91
+ params = prepare_params(params)
92
+ req.setParams(params)
93
+ end
94
+ end
95
+
96
+ end
97
+
98
+ end
@@ -0,0 +1,49 @@
1
+ module VW
2
+ class ResponseListener
3
+ attr_accessor :serializer, :callback, :network_response, :request_url, :request_params, :request_method
4
+
5
+ def initialize(serializer, &block)
6
+ @serializer = serializer
7
+ @callback = block
8
+ end
9
+
10
+ def onResponse(response)
11
+ response_object = expect_json? ? Moran.parse(response.to_s) : response
12
+ create_result(@network_response, response_object, nil)
13
+ end
14
+
15
+ def onErrorResponse(error)
16
+ if network_response = error.networkResponse
17
+ data = network_response.data
18
+ end
19
+ create_result(network_response, data, error.toString)
20
+ end
21
+
22
+ private
23
+
24
+ def expect_json?
25
+ serializer == :json
26
+ end
27
+
28
+ def create_result(response, response_object, error)
29
+ request = HTTPResult.new(response, response_object, error)
30
+ request.request_url = @request_url
31
+ request.request_params = @request_params
32
+ request.request_method = @request_method
33
+
34
+ if VW::SessionClient.debug
35
+ mp request.to_s
36
+ end
37
+ callback.call request
38
+ end
39
+
40
+ def dump_network_error(error)
41
+ puts error.toString
42
+ if response = error.networkResponse
43
+ puts response.statusCode
44
+ puts response.headers
45
+ puts response.data
46
+ end
47
+ end
48
+ end
49
+ end