bluepotion 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e8c33ac84159dff9873425c197d5c9242c67768f
4
- data.tar.gz: b036ad3025714de737321d4f416b9c311ce0b6b4
3
+ metadata.gz: fdb0d8c6161c235baac6480838e5e1cabe94c6fa
4
+ data.tar.gz: b908f87be8c23fd810d18a48052bca355ad6c731
5
5
  SHA512:
6
- metadata.gz: 27935ab418a592ba44f19dec919c95e91a39140b3bd6a8f85c4ca7d74609ebcbe5304f1615112fd67e7b61d275b66e7a467c04bf3d99864449a89e5c913987f4
7
- data.tar.gz: 08d769a8538ec46d1b564ff78fd330d227e7c45a9487488b9b119c72603cc48367678ca0c7f1cecd0d8fe1ad03ecedce7899981caa50c664d2d12ebac0e653b1
6
+ metadata.gz: caf24b6c2f5646512dff78031b1e02e3ff7149013f15da9ec9daaee3aa51329f45ef14c5eaed5a26a12c587732e90e38a2e82e673e36155f986eee5bbce865da
7
+ data.tar.gz: def61d81138b2120c82ac3745a59e96879d7076b2f9b8810e4a0c188b31060ac8fb992f2f5f07789f3c11f63631d5f692ecbda79aaf7e1d14f4f8d0417bd6eeb
@@ -0,0 +1,62 @@
1
+ ######################################################
2
+ # Example usage - since this is in PMApplication
3
+ ######################################################
4
+ # app.alert(title: "Hey There", message: "Want a sandwich?") do |choice|
5
+ # case choice
6
+ # when "OK"
7
+ # mp "Here's your sandwich"
8
+ # when "Cancel"
9
+ # mp "Fine!"
10
+ # end
11
+ # end
12
+
13
+ # Generic AlertDialog
14
+ class AlertDialog < Android::App::DialogFragment
15
+
16
+ def initialize(options={}, &block)
17
+
18
+ # Defaults
19
+ @options = {
20
+ theme: Android::App::AlertDialog::THEME_HOLO_LIGHT,
21
+ title: "Alert!",
22
+ message: "",
23
+ positive_button: "OK",
24
+ negative_button: "Cancel",
25
+ positive_button_handler: self,
26
+ negative_button_handler: self,
27
+ show: true
28
+ }.merge(options)
29
+
30
+ @callback = block
31
+
32
+ self.show if @options[:show]
33
+ self
34
+ end
35
+
36
+ def show(activity=rmq.activity)
37
+ super(activity.fragmentManager, "alert_dialog")
38
+ end
39
+
40
+ def onCreateDialog(saved_instance_state)
41
+ builder = Android::App::AlertDialog::Builder.new(getActivity(), @options[:theme])
42
+
43
+ builder.title = @options[:title]
44
+ builder.message = @options[:message]
45
+
46
+ # Add buttons if they are set
47
+ builder.setPositiveButton(@options[:positive_button], @options[:positive_button_handler]) if @options[:positive_button]
48
+ builder.setNegativeButton(@options[:negative_button], @options[:negative_button_handler]) if @options[:negative_button]
49
+
50
+ # Add custom view?
51
+ builder.view = @options[:view] if @options[:view]
52
+
53
+ # DONE!
54
+ builder.create()
55
+ end
56
+
57
+ def onClick(dialog, id)
58
+ button_text = (id == Android::App::AlertDialog::BUTTON_POSITIVE) ? @options[:positive_button] : @options[:negative_button]
59
+ @callback.call(button_text) if @callback
60
+ end
61
+
62
+ end
@@ -13,7 +13,7 @@
13
13
  # @example
14
14
  # # Create a session and do a single HTML get. It's better
15
15
  # # to use the shared session below.
16
- # app.net.get("http://google.com")do |response|
16
+ # app.net.get("http://google.com") do |response|
17
17
  # mp response.object # <- HTML
18
18
  # end
19
19
  #
@@ -9,6 +9,7 @@ module Potion
9
9
  Bundle = Android::Os::Bundle
10
10
  Environment = Android::Os::Environment
11
11
  Uri = Android::Net::Uri
12
+ Url = Java::Net::URL
12
13
  ArrayAdapter = Android::Widget::ArrayAdapter
13
14
  BaseAdapter = Android::Widget::BaseAdapter
14
15
  Dialog = Android::App::Dialog
@@ -37,6 +38,7 @@ module Potion
37
38
 
38
39
  # Media
39
40
  File = Java::Io::File
41
+ FileOutputStream = Java::Io::FileOutputStream
40
42
  MediaStore = Android::Provider::MediaStore
41
43
  Contacts = Android::Provider::ContactsContract::Contacts
42
44
  end
@@ -18,6 +18,15 @@
18
18
  mp "PMActivity on_create", debugging_only: true
19
19
  end
20
20
 
21
+ # These 2 methods are needed to pass on to inherited activities
22
+ def onActivityResult(request_code, result_code, data)
23
+ on_activity_result(request_code, result_code, data)
24
+ end
25
+
26
+ def on_activity_result(request_code, result_code, data)
27
+ # Abstract
28
+ end
29
+
21
30
  def onResume
22
31
  super
23
32
  on_resume
@@ -44,8 +53,11 @@
44
53
  def on_create_menu(_); end
45
54
 
46
55
  def onOptionsItemSelected(item)
56
+ home_const = 16908332 # R.id.home
57
+ return onBackPressed if item.getItemId == home_const
47
58
  # Don't call super if method returns false
48
- super unless on_options_item_selected(item) == false
59
+ return true if on_options_item_selected(item) == false
60
+ super
49
61
  end
50
62
 
51
63
  def open(screen, options={})
@@ -22,7 +22,7 @@
22
22
  def open_fragment(frag, options={})
23
23
  mp frag
24
24
  mgr = fragmentManager.beginTransaction
25
- mgr.add(@fragment_container.getId, frag, "screen-#{fragmentManager.getBackStackEntryCount + 1}")
25
+ mgr.replace(@fragment_container.getId, frag, "screen-#{fragmentManager.getBackStackEntryCount + 1}")
26
26
  mgr.addToBackStack(nil)
27
27
  mgr.commit
28
28
  frag
@@ -54,5 +54,11 @@
54
54
  self.fragment.on_options_item_selected(item) if self.fragment
55
55
  end
56
56
 
57
+ def on_activity_result(request_code, result_code, data)
58
+ if @fragment && @fragment.respond_to?(:handle_activity_result)
59
+ @fragment.activity_result(request_code, result_code, data)
60
+ end
61
+ end
62
+
57
63
  end
58
64
  #end
@@ -90,7 +90,7 @@
90
90
  @view.setId Potion::ViewIdGenerator.generate
91
91
  end
92
92
 
93
- action_bar.hide if hide_action_bar?
93
+ set_up_action_bar(self.class.action_bar_options)
94
94
 
95
95
  on_create_view(inflater, parent, saved_instance_state)
96
96
 
@@ -155,41 +155,6 @@
155
155
  end
156
156
  def on_detach; end
157
157
 
158
- def set_title
159
- self.title = self.class.bars_title
160
- end
161
-
162
- def title
163
- @title
164
- end
165
- def title=(value)
166
- @title = value
167
-
168
- if a = self.activity
169
- if a_bar = self.action_bar
170
- a_bar.title = value
171
- end
172
- a.title = value
173
- end
174
- end
175
-
176
- private
177
-
178
- def build_and_tag_xml_views
179
- return unless @xml_resource
180
-
181
- self.rmq.all.each do |view|
182
- if ren = view.resource_entry_name
183
- self.rmq.build(view).tag(ren.to_sym)
184
- end
185
- end
186
- end
187
-
188
- def hide_action_bar?
189
- # RM-???: comparing nil to false causes ART crash
190
- !self.class.show_action_bar.nil? && self.class.show_action_bar == false
191
- end
192
-
193
158
  end
194
159
 
195
160
  #end
@@ -27,7 +27,7 @@
27
27
  @view.setId Potion::ViewIdGenerator.generate
28
28
  end
29
29
 
30
- action_bar.hide if hide_action_bar?
30
+ set_up_action_bar(self.class.action_bar_options)
31
31
 
32
32
  on_create_view(inflater, parent, saved_instance_state)
33
33
 
@@ -90,41 +90,6 @@
90
90
  end
91
91
  def on_detach; end
92
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
-
111
- private
112
-
113
- def build_and_tag_xml_views
114
- return unless @xml_resource
115
-
116
- self.rmq.all.each do |view|
117
- if ren = view.resource_entry_name
118
- self.rmq.build(view).tag(ren.to_sym)
119
- end
120
- end
121
- end
122
-
123
- def hide_action_bar?
124
- # RM-???: comparing nil to false causes ART crash
125
- !self.class.show_action_bar.nil? && self.class.show_action_bar == false
126
- end
127
-
128
93
  end
129
94
 
130
95
  #end
@@ -6,9 +6,7 @@
6
6
  end
7
7
 
8
8
  module ClassMethods
9
- attr_reader :xml_resource, :show_action_bar, :bars_title
10
-
11
- @show_action_bar = true
9
+ attr_reader :xml_resource, :bars_title
12
10
 
13
11
  def stylesheet(style_sheet_class)
14
12
  @rmq_style_sheet_class = style_sheet_class
@@ -23,12 +21,22 @@
23
21
  end
24
22
  alias_method :uses_xml, :xml_layout
25
23
 
26
- def action_bar(show_action_bar)
27
- @show_action_bar = show_action_bar
24
+ # Sets up the action bar for this screen.
25
+ #
26
+ # Example:
27
+ # action_bar true, back: true, icon: true,
28
+ # custom_icon: "resourcename", custom_back: "custombackicon"
29
+ #
30
+ def action_bar(show_action_bar, opts={})
31
+ @action_bar_options = ({show:true, back: true, icon: false}).merge(opts).merge({show: show_action_bar})
28
32
  end
29
33
  alias_method :nav_bar, :action_bar
30
34
  alias_method :uses_action_bar, :action_bar
31
35
 
36
+ def action_bar_options
37
+ @action_bar_options ||= action_bar(true, {})
38
+ end
39
+
32
40
  def title(new_title)
33
41
  @bars_title = new_title
34
42
  #self.activity.title = new_title
@@ -69,9 +77,9 @@
69
77
  self.getView
70
78
  end
71
79
 
72
- def on_load
73
- # abstract
74
- end
80
+ # abstract methods
81
+ def on_load; end
82
+ def on_return(opts={}); end
75
83
 
76
84
  def color(*params)
77
85
  RMQ.color(*params)
@@ -175,6 +183,12 @@
175
183
  else
176
184
  # Closing current screen or activity if no screens left
177
185
  act.close_fragment if act.fragment
186
+ end
187
+
188
+ if act.fragment
189
+ act.fragment.set_up_action_bar
190
+ act.fragment.on_return(options)
191
+ else
178
192
  act.finish unless act.fragment
179
193
  end
180
194
  end
@@ -196,19 +210,29 @@
196
210
 
197
211
  def hide_keyboard
198
212
  input_manager = activity.getSystemService(Android::Content::Context::INPUT_METHOD_SERVICE)
199
- input_manager.hideSoftInputFromWindow(view.getWindowToken(), 0);
213
+ input_manager.hideSoftInputFromWindow(view.getWindowToken(), 0)
200
214
  end
201
215
 
202
216
  def action_bar
203
- if a = activity
204
- a.getActionBar
205
- end
217
+ activity && activity.getActionBar
206
218
  end
207
219
 
208
220
  def menu
209
221
  activity.menu
210
222
  end
211
223
 
224
+ def set_up_action_bar(options={})
225
+ if options[:show]
226
+ action_bar.show
227
+ action_bar.setDisplayHomeAsUpEnabled(!!options[:back])
228
+ action_bar.setDisplayShowHomeEnabled(!!options[:icon])
229
+ action_bar.setIcon(image.resource(options[:custom_icon].to_s)) if options[:custom_icon]
230
+ action_bar.setHomeAsUpIndicator(image.resource(options[:custom_back].to_s)) if options[:custom_back]
231
+ else
232
+ action_bar.hide
233
+ end
234
+ end
235
+
212
236
  # Example: add_action_bar_button(title: "My text", show: :if_room)
213
237
  def add_action_bar_button(options={})
214
238
  @action_bar ||= { button_actions: {} }
@@ -245,5 +269,33 @@
245
269
  end
246
270
  end
247
271
 
272
+ def build_and_tag_xml_views
273
+ return unless @xml_resource
274
+
275
+ self.rmq.all.each do |view|
276
+ if ren = view.resource_entry_name
277
+ self.rmq.build(view).tag(ren.to_sym)
278
+ end
279
+ end
280
+ end
281
+
282
+ def set_title
283
+ self.title = self.class.bars_title
284
+ end
285
+
286
+ def title
287
+ @title
288
+ end
289
+ def title=(value)
290
+ @title = value
291
+
292
+ if a = self.activity
293
+ if a_bar = self.action_bar
294
+ a_bar.title = value
295
+ end
296
+ a.title = value
297
+ end
298
+ end
299
+
248
300
  end
249
301
  #end
@@ -25,6 +25,14 @@
25
25
  context.applicationInfo
26
26
  end
27
27
 
28
+ def package_manager
29
+ context.getPackageManager
30
+ end
31
+
32
+ def name
33
+ application_info.loadLabel(package_manager)
34
+ end
35
+
28
36
  def identifier
29
37
  application_info.packageName
30
38
  end
@@ -81,6 +89,10 @@
81
89
  RMQResource
82
90
  end
83
91
 
92
+ def r
93
+ RMQResource
94
+ end
95
+
84
96
  def net
85
97
  BluePotionNet
86
98
  end
@@ -99,6 +111,10 @@
99
111
  Android::Widget::Toast.makeText(rmq.activity, message, message_length).show
100
112
  end
101
113
 
114
+ def alert(options={}, &block)
115
+ AlertDialog.new(options, &block)
116
+ end
117
+
102
118
  class << self
103
119
  attr_accessor :current_application, :home_screen_class
104
120
 
@@ -0,0 +1,38 @@
1
+ ###### EXAMPLE USAGE #######
2
+ #@phud = ProgressHUD.new("Loading Widgets")
3
+ #@phud.show
4
+ #@phud.title = "Widgets Almost Completed!"
5
+ #@phud.dismiss
6
+
7
+ class ProgressHUD < Android::App::DialogFragment
8
+
9
+ def initialize(title="Loading")
10
+ @title = title
11
+ end
12
+
13
+ def show(activity=rmq.activity)
14
+ super(activity.fragmentManager, "progress")
15
+ end
16
+
17
+ def onCreateDialog(saved_instance_state)
18
+ builder = Android::App::AlertDialog::Builder.new(activity,
19
+ Android::App::AlertDialog::THEME_HOLO_LIGHT)
20
+
21
+ progress = Android::Widget::ProgressBar.new(activity)
22
+ progress.setBackgroundColor(Android::Graphics::Color::TRANSPARENT)
23
+ builder.setView(progress)
24
+ .setTitle(@title)
25
+
26
+ @created_dialog = builder.create()
27
+ end
28
+
29
+ def title=(new_title)
30
+ @created_dialog.title = new_title if @created_dialog
31
+ end
32
+
33
+ def hide
34
+ self.dismiss
35
+ end
36
+ alias_method :close, :hide
37
+
38
+ end
@@ -66,10 +66,10 @@ class RMQ
66
66
  end
67
67
  end
68
68
 
69
- def wrap(*views)
69
+ def wrap(view_one, *views) # These strange params is because of RMA bug
70
70
  views = [views] unless views.is_a?(Potion::ArrayList) # TODO, WTF, RM bug?
71
+ views.unshift(view_one)
71
72
  views.flatten!
72
-
73
73
  views.select!{ |v| v.is_a?(Potion::View) }
74
74
  RMQ.create_with_array_and_selectors(views, views, @originated_from, self)
75
75
  end
@@ -10,7 +10,7 @@ class RMQ
10
10
  @_selectors
11
11
  end
12
12
 
13
- def match(view, new_selectors)
13
+ def match(view, new_selectors, dummy=nil)
14
14
  out = false
15
15
 
16
16
  # This method is written strange because the return in this example doesn't actually return (RM bug)
@@ -110,6 +110,10 @@ class RMQ
110
110
 
111
111
  end
112
112
 
113
+ def find!(*args) # Do not alias this, strange bugs happen where classes don't have methods
114
+ self.find(*args).get
115
+ end
116
+
113
117
  # @return [RMQ] A new rmq instance reducing selected views to those that match selectors provided
114
118
  #
115
119
  # @param selectors your selector
@@ -0,0 +1,219 @@
1
+ module RubyMotionQuery
2
+ class RMQ
3
+
4
+ # @return [Validation]
5
+ def self.validation
6
+ Validation
7
+ end
8
+
9
+ # @return [Validation]
10
+ def validation
11
+ Validation
12
+ end
13
+
14
+ # @return [RMQ]
15
+ def validates(rule, options={})
16
+ selected.each do |view|
17
+ view.rmq_data.validations << Validation.new(rule, options)
18
+ end
19
+ self
20
+ end
21
+
22
+ # @return [RMQ]
23
+ def clear_validations!
24
+ selected.each do |view|
25
+ view.rmq_data.validations = []
26
+ end
27
+ self
28
+ end
29
+
30
+ # This method validates all the selected and is responsible
31
+ # for calling invalid/valid events
32
+ #
33
+ # @return [Boolean] false if any validations fail
34
+ def valid?
35
+ result = true
36
+
37
+ selected.each do |view|
38
+ view.rmq_data.validations.each do |validation|
39
+
40
+ has_events = view.rmq_data.events
41
+
42
+ if validation.valid?(rmq(view).data)
43
+ if has_events && view.rmq_data.events.has_event?(:valid)
44
+ view.rmq_data.events[:valid].fire!
45
+ end
46
+ else
47
+ if has_events && view.rmq_data.events.has_event?(:invalid)
48
+ view.rmq_data.events[:invalid].fire!
49
+ end
50
+ result = false
51
+ end
52
+ end
53
+ end
54
+ return result
55
+ end
56
+
57
+ # @return [Array] of error messages for failed validations
58
+ def validation_errors
59
+ errors = []
60
+ selected.each do |view|
61
+ view.rmq_data.validations.each do |validation|
62
+ unless validation.valid_status
63
+ default_error = "Validation Error - input requires valid #{validation.rule_name}."
64
+ rule_message = view.rmq_data.validation_errors[validation.rule_name] || default_error
65
+ errors.push(rule_message)
66
+ end
67
+ end
68
+ end
69
+ return errors
70
+ end
71
+
72
+ # @return [Array] of views where validations have failed
73
+ def invalid
74
+ selected.reject do |view|
75
+ view.rmq_data.validations.map{ |validation| validation.valid_status }.reduce(:&)
76
+ end
77
+ end
78
+
79
+ # @return [Array] of views where validations have not failed
80
+ def valid
81
+ selected.select do |view|
82
+ view.rmq_data.validations.map{ |validation| validation.valid_status }.reduce(:&)
83
+ end
84
+ end
85
+
86
+ end # End RMQ
87
+
88
+ class Validation
89
+ attr_reader :valid_status, :rule_name
90
+
91
+ ####################################################
92
+ # THIS IS SIGNIFICANTLY DIFFERENT FROM iOS BECAUSE
93
+ # Regexp object is not available - but Java is
94
+ ####################################################
95
+
96
+ # Validation Regex from jQuery validation -> https://github.com/jzaefferer/jquery-validation/blob/master/src/core.js#L1094-L1200
97
+ EMAIL = '^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$'
98
+ URL = '^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:|@)|\/|\?)*)?$'
99
+ DATEISO = '^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$'
100
+ NUMBER = '^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$'
101
+ DIGITS = '^\d+$'
102
+ # Other Fun by http://www.freeformatter.com/regex-tester.html
103
+ IPV4 = '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
104
+ TIME = '^(20|21|22|23|[01]\d|\d)((:[0-5]\d){1,2})$'
105
+ # Future Password strength validations -> http://stackoverflow.com/questions/5142103/regex-for-password-strength
106
+ USZIP = '^\d{5}(-\d{4})?$'
107
+ # UK Postal Code regex from: http://stackoverflow.com/a/7259020/814123
108
+ UKZIP = '^(GIR ?0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]([0-9ABEHMNPRV-Y])?)|[0-9][A-HJKPS-UW]) ?[0-9][ABD-HJLNP-UW-Z]{2})$'
109
+ # 7 or 10 digit number, delimiters are spaces, dashes, or periods
110
+ USPHONE = '^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]‌​)\s*)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-‌​9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})$'
111
+ # International Phone numbers
112
+ INTLPHONE = '^(\(?\+?[0-9]*\)?)?[0-9_\- \(\)]*$'
113
+ # Strong password (at least [8 chars, 1 upper, 1 lower, 1 number])
114
+ STRONGPW = '^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{8,}$'
115
+ # Has at least 1 uppercase letter
116
+ HASUPPER = '^(?=.*[A-Z]).+$'
117
+ # Has at least 1 lowercase letter
118
+ HASLOWER = '^(?=.*[a-z]).+$'
119
+ # Has some kind of value not just whitespace (doesn't require data to be stripped)
120
+ PRESENCE = '\S+'
121
+
122
+ @@validation_methods = {
123
+ :email => lambda { |value, opts| value.toString.matches(EMAIL)},
124
+ :url => lambda { |value, opts| value.toString.matches(URL)},
125
+ :dateiso => lambda { |value, opts| value.toString.matches(DATEISO)},
126
+ :number => lambda { |value, opts| value.toString.matches(NUMBER)},
127
+ :digits => lambda { |value, opts| value.toString.matches(DIGITS)},
128
+ :ipv4 => lambda { |value, opts| value.toString.matches(IPV4)},
129
+ :time => lambda { |value, opts| value.toString.matches(TIME)},
130
+ :uszip => lambda { |value, opts| value.toString.matches(USZIP)},
131
+ :ukzip => lambda { |value, opts| value.toString.matches(UKZIP)},
132
+ :usphone => lambda { |value, opts| value.toString.matches(USPHONE)},
133
+ :intlphone => lambda { |value, opts| value.toString.matches(INTLPHONE)},
134
+ :strong_password => lambda { |value, opts| value.toString.matches(STRONGPW)},
135
+ :has_upper => lambda { |value, opts| value.toString.matches(HASUPPER)},
136
+ :has_lower => lambda { |value, opts| value.toString.matches(HASLOWER)},
137
+ :presence => lambda { |value, opts| value.toString.matches(PRESENCE)},
138
+ :length => lambda { |value, opts|
139
+ opts = {
140
+ exact_length: nil,
141
+ max_length: Float::INFINITY,
142
+ min_length: 0,
143
+ strip: false
144
+ }.merge(opts)
145
+
146
+ # Range magic 8..16
147
+ if opts[:exact_length].is_a? Range
148
+ opts[:min_length] = opts[:exact_length].begin
149
+ opts[:max_length] = opts[:exact_length].end
150
+ opts[:exact_length] = nil
151
+ end
152
+
153
+ # allowing option to strip input before assessing length
154
+ value.strip! if opts[:strip]
155
+
156
+ # check length validation
157
+ v = if opts[:exact_length] then (value.length == opts[:exact_length]) else true end
158
+ v = v && value.length <= opts[:max_length]
159
+ v = v && value.length >= opts[:min_length]
160
+ },
161
+ :custom => lambda { |value, opts| value.toString.matches(opts[:regex])},
162
+ }
163
+
164
+
165
+ def initialize(rule, options={})
166
+ @rule = @@validation_methods[rule]
167
+ raise "RMQ validation error: :#{rule} is not one of the supported validation methods." unless @rule
168
+ @rule_name = rule
169
+ @options = options
170
+ @valid_status = true
171
+ end
172
+
173
+ def valid?(data, options={})
174
+ @options = options.merge(@options)
175
+
176
+ # shortcircuit for universal validation parameters
177
+ return true if universal_validation_checks(data, @options)
178
+
179
+ @valid_status = @rule.call(data, @options)
180
+ end
181
+
182
+ # this method shortcuts specific validation rules. As such it should only be
183
+ # added to for universal validation needs. It must be kept as efficient as possible.
184
+ def universal_validation_checks (data, options={})
185
+ # shortcircuit if debugging
186
+ return true if RubyMotionQuery::RMQ.debugging?
187
+ # allow blank data if specified
188
+ return true if (options[:allow_blank] && (data.nil? || data.empty?))
189
+ # allow whitelist data if specified
190
+ return true if (options[:white_list] && options[:white_list].include?(data))
191
+
192
+ false
193
+ end
194
+
195
+ class << self
196
+
197
+ # Add tags
198
+ # @example
199
+ # rmq.validation.valid?('test@test.com', :email)
200
+ # rmq.validation.valid?(53.8, :number)
201
+ # rmq.validation.valid?(54, :digits)
202
+ # rmq.validation.valid?('https://www.tacoland.com', :url)
203
+ # rmq.validation.valid?('2014-03-02', :dateiso)
204
+ # rmq.validation.valid?('', :email, allow_blank: true)
205
+ #
206
+ # @return [Boolean]
207
+ def valid?(value, rule, options={})
208
+ Validation.new(rule).valid?(value, options)
209
+ end
210
+
211
+ def add_validator(rule, &block)
212
+ raise(ArgumentError, "add_validator requires a block") if block.nil?
213
+
214
+ @@validation_methods[rule] = block
215
+ end
216
+
217
+ end
218
+ end
219
+ end
@@ -1,3 +1,3 @@
1
1
  module BluePotion
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bluepotion
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - InfiniteRed
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-06-25 00:00:00.000000000 Z
12
+ date: 2015-07-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -41,6 +41,7 @@ files:
41
41
  - bin/bluepotion_add_line_numbers
42
42
  - bin/bluepotion_remove_line_numbers
43
43
  - lib/bluepotion.rb
44
+ - lib/project/alert_dialog/alert_dialog.rb
44
45
  - lib/project/blue_potion_net.rb
45
46
  - lib/project/compatibility/dispatch.rb
46
47
  - lib/project/compatibility/motion_keychain.rb
@@ -64,6 +65,7 @@ files:
64
65
  - lib/project/pro_motion/fragments/pm_screen_module.rb
65
66
  - lib/project/pro_motion/pm_application.rb
66
67
  - lib/project/pro_motion/support/pm_hash_bundle.rb
68
+ - lib/project/progress_hud/progress_hud.rb
67
69
  - lib/project/ruby_motion_query/rmq/actions.rb
68
70
  - lib/project/ruby_motion_query/rmq/base.rb
69
71
  - lib/project/ruby_motion_query/rmq/data.rb
@@ -93,6 +95,7 @@ files:
93
95
  - lib/project/ruby_motion_query/rmq_resource.rb
94
96
  - lib/project/ruby_motion_query/rmq_screen_data.rb
95
97
  - lib/project/ruby_motion_query/rmq_stylesheet.rb
98
+ - lib/project/ruby_motion_query/rmq_validation.rb
96
99
  - lib/project/ruby_motion_query/rmq_view_data.rb
97
100
  - lib/project/ruby_motion_query/stylers/rmq_button_styler.rb
98
101
  - lib/project/ruby_motion_query/stylers/rmq_image_button_styler.rb
@@ -133,10 +136,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
136
  version: '0'
134
137
  requirements: []
135
138
  rubyforge_project:
136
- rubygems_version: 2.4.6
139
+ rubygems_version: 2.4.5
137
140
  signing_key:
138
141
  specification_version: 4
139
142
  summary: BluePotion - Just like RedPotion, but for Android. The best combination of
140
143
  RubyMotion tools and libraries for Android
141
144
  test_files: []
142
- has_rdoc: