bluepotion 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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: