ruboto-core 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/Gemfile +1 -1
  2. data/Gemfile.lock +1 -1
  3. data/README.md +42 -3
  4. data/Rakefile +5 -0
  5. data/assets/Rakefile +72 -7
  6. data/assets/assets/scripts/ruboto.rb +124 -71
  7. data/assets/res/drawable-hdpi/icon.png +0 -0
  8. data/assets/res/drawable-ldpi/icon.png +0 -0
  9. data/assets/res/drawable-mdpi/icon.png +0 -0
  10. data/assets/samples/sample_activity.rb +3 -3
  11. data/assets/samples/sample_activity_test.rb +21 -0
  12. data/assets/samples/sample_broadcast_receiver.rb +1 -1
  13. data/assets/samples/sample_broadcast_receiver_test.rb +1 -0
  14. data/assets/samples/sample_service.rb +2 -1
  15. data/assets/samples/sample_service_test.rb +1 -0
  16. data/assets/src/InheritingActivity.java +6 -4
  17. data/assets/src/RubotoActivity.java +17 -5
  18. data/assets/src/org/ruboto/Script.java +30 -17
  19. data/assets/src/org/ruboto/test/ActivityTest.java +58 -0
  20. data/assets/src/org/ruboto/test/InstrumentationTestRunner.java +102 -0
  21. data/assets/test/assets/scripts/test_helper.rb +9 -0
  22. data/bin/ruboto +3 -920
  23. data/lib/java_class_gen/android_api.xml +1 -1
  24. data/lib/ruboto.rb +15 -0
  25. data/lib/ruboto/api.rb +21 -0
  26. data/lib/ruboto/commands/base.rb +373 -0
  27. data/lib/ruboto/core_ext/array.rb +6 -0
  28. data/lib/ruboto/core_ext/object.rb +10 -0
  29. data/lib/ruboto/util/asset_copier.rb +20 -0
  30. data/lib/ruboto/util/build.rb +183 -0
  31. data/lib/ruboto/util/code_formatting.rb +22 -0
  32. data/lib/ruboto/util/log_action.rb +20 -0
  33. data/lib/ruboto/util/main_fix.rb +13 -0
  34. data/lib/ruboto/util/objectspace.rb +8 -0
  35. data/lib/ruboto/util/scan_in_api.rb +40 -0
  36. data/lib/ruboto/util/update.rb +102 -0
  37. data/lib/ruboto/util/verify.rb +59 -0
  38. data/lib/ruboto/util/xml_element.rb +197 -0
  39. data/test/app_test.rb +44 -0
  40. data/test/test_helper.rb +4 -0
  41. metadata +41 -14
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source :gemcutter
1
+ source :rubygems
2
2
 
3
3
  gem 'main'
4
4
  gem 'jruby-jars'
@@ -3,7 +3,7 @@ GEM
3
3
  specs:
4
4
  arrayfields (4.7.4)
5
5
  fattr (2.1.0)
6
- jruby-jars (1.5.3)
6
+ jruby-jars (1.5.6)
7
7
  main (4.2.0)
8
8
  arrayfields (>= 4.7.4)
9
9
  fattr (>= 2.1.0)
data/README.md CHANGED
@@ -46,7 +46,7 @@ Version values must be specified using'android-' and the sdk level number (e.g.,
46
46
  <a name="class_generator"></a>
47
47
  ### Class generator
48
48
 
49
- Generates a Java class (Activity, Service, or BroadcastReceiver) associated with a specific ruboto script.
49
+ Generates a Java class (Activity, Service, or BroadcastReceiver) associated with a specific ruboto script. The generator also generates a corrsponding test script.
50
50
 
51
51
  $ ruboto gen class ClassName --name YourObjectName
52
52
  Ex:
@@ -61,7 +61,7 @@ For classes that need subclassing (e.g., PhoneStateListener, SQLiteOpenHelper, V
61
61
 
62
62
  $ ruboto gen subclass AndroidPackageAndClassName --name YourClassName --method_base all-on-or-none --method_include methods --method_exclude methods
63
63
  Ex:
64
- $ ruboto gen class android.telephony.PhoneStateListener --name MyPhoneStateListener
64
+ $ ruboto gen subclass android.telephony.PhoneStateListener --name MyPhoneStateListener --method_base on
65
65
 
66
66
  For interfaces that need implementing (e.g., OnClickListener or SensorListener)
67
67
 
@@ -200,6 +200,41 @@ The arguments passed to the block you give `handle_` methods are the same as the
200
200
 
201
201
  Activities also have some special methods defined to make things easier. The easiest way to get an idea of what they are is looking over the [demo scripts](http://github.com/ruboto/ruboto-irb/tree/master/assets/demo-scripts/). You can also read the [ruboto.rb file](http://github.com/ruboto/ruboto-core/blob/master/assets/assets/scripts/ruboto.rb) where everything is defined.
202
202
 
203
+ Testing
204
+ -------
205
+
206
+ For each generated class, a ruby test script is created in the test/assets/scripts directory.
207
+ For example if you generate a RubotoSampleAppActivity a file test/assets/scripts/ruboto_sample_app_activity_test.rb
208
+ file is created containing a sample test script:
209
+
210
+ activity Java::org.ruboto.sample_app.RubotoSampleAppActivity
211
+
212
+ setup do |activity|
213
+ start = Time.now
214
+ loop do
215
+ @text_view = activity.findViewById(42)
216
+ break if @text_view || (Time.now - start > 60)
217
+ sleep 1
218
+ end
219
+ assert @text_view
220
+ end
221
+
222
+ test('initial setup') do |activity|
223
+ assert_equal "What hath Matz wrought?", @text_view.text
224
+ end
225
+
226
+ test('button changes text') do |activity|
227
+ button = activity.findViewById(43)
228
+ button.performClick
229
+ assert_equal "What hath Matz wrought!", @text_view.text
230
+ end
231
+
232
+ You run the tests for your app using ant or rake
233
+
234
+ $ jruby -S rake test
235
+
236
+ $ cd test ; ant run-tests
237
+
203
238
  Contributing
204
239
  ------------
205
240
 
@@ -211,6 +246,10 @@ Want to contribute? Great! Meet us in #ruboto on irc.freenode.net, fork the proj
211
246
  * As you gain wisdom, contribute it to [the wiki](http://github.com/ruboto/ruboto-core/wiki/)
212
247
  * When you gain enough wisdom, reconsider whether you could fork the project.
213
248
 
249
+ If contributing code to the project, please run the exising tests and add tests for your changes. You run the tests using rake
250
+
251
+ $ jruby -S rake test
252
+
214
253
  Getting Help
215
254
  ------------
216
255
 
@@ -244,7 +283,7 @@ Garrett is a "playground for Mirah exploration on Android."
244
283
 
245
284
 
246
285
  Domo Arigato
247
- -----
286
+ ------------
248
287
 
249
288
  Thanks go to:
250
289
 
data/Rakefile CHANGED
@@ -8,3 +8,8 @@ task :release do
8
8
  `gem push #{Dir['ruboto-core-*.gem'][-1]}`
9
9
  end
10
10
 
11
+ task :test do
12
+ Dir['test/*_test.rb'].each do |f|
13
+ load f
14
+ end
15
+ end
@@ -5,8 +5,12 @@
5
5
  #
6
6
 
7
7
 
8
- raise "Needs JRuby 1.5" unless RUBY_PLATFORM =~ /java/
9
- require 'ant'
8
+ if RUBY_PLATFORM =~ /java/
9
+ puts "Detected JRuby. Loading ANT."
10
+ require 'ant'
11
+ ant_loaded = true
12
+ end
13
+
10
14
  require 'rake/clean'
11
15
  require 'rexml/document'
12
16
 
@@ -16,13 +20,13 @@ stdlib = jars.grep(/stdlib/).first #libs/jruby-stdlib-VERSION.jar
16
20
  jruby_jar = jars.grep(/core/).first #libs/jruby-core-VERSION.jar
17
21
  stdlib_precompiled = File.join(generated_libs, 'jruby-stdlib-precompiled.jar')
18
22
  jruby_ruboto_jar = File.join(generated_libs, 'jruby-ruboto.jar')
19
- ant.property :name=>'external.libs.dir', :value => generated_libs
23
+ ant.property :name=>'external.libs.dir', :value => generated_libs if ant_loaded
20
24
  dirs = ['tmp/ruby', 'tmp/precompiled', generated_libs]
21
25
  dirs.each { |d| directory d }
22
26
 
23
27
  CLEAN.include('tmp', 'bin', generated_libs)
24
28
 
25
- ant_import
29
+ ant_import if ant_loaded
26
30
 
27
31
  file stdlib_precompiled => :compile_stdlib
28
32
  file jruby_ruboto_jar => generated_libs do
@@ -74,9 +78,69 @@ task :publish => :align do
74
78
  puts "#{build_project_name}.apk is ready for the market!"
75
79
  end
76
80
 
81
+ task :start_app do
82
+ `adb shell am start -a android.intent.action.MAIN -n #{package}/.#{main_activity}`
83
+ end
84
+
85
+ task :stop_app do
86
+ `adb shell ps | grep #{package} | awk '{print $2}' | xargs adb shell kill`
87
+ end
88
+
89
+ task :restart => [:stop_app, :start_app]
90
+
91
+ task :uninstall do
92
+ system "adb uninstall #{package}"
93
+ end
94
+
95
+ namespace :install do
96
+ desc 'Build, install, and restart the application'
97
+ task :restart => [:install, :start_app]
98
+ namespace :restart do
99
+ desc 'Uninstall, build, install, and restart the application'
100
+ task :clean => [:uninstall, :install, :start_app]
101
+ end
102
+ end
103
+
104
+ desc 'Copy scripts to emulator'
77
105
  task :update_scripts do
78
- Dir['assets/scripts/*.rb'].each do |script|
79
- `adb push #{script} /data/data/#{package}/files/scripts`
106
+ manifest
107
+ Dir.chdir('assets') do
108
+ # Add more directories here if you want them copied to the emulator
109
+ ['scripts'].each do |script_dir|
110
+ Dir["#{script_dir}/*"].each do |script|
111
+ next if File.directory? script
112
+ `adb push #{script} /data/data/#{package}/files/#{script_dir}`
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ namespace :update_scripts do
119
+ desc 'Copy scripts to emulator and restart the app'
120
+ task :restart => [:stop_app, :update_scripts, :start_app]
121
+ end
122
+
123
+ task :update_test_scripts do
124
+ Dir['test/assets/scripts/*.rb'].each do |script|
125
+ `adb push #{script} /data/data/#{package}.tests/files/scripts/`
126
+ end
127
+ `adb shell ps | grep #{package}.tests | awk '{print $2}' | xargs adb shell kill`
128
+ end
129
+
130
+ task :test => :uninstall do
131
+ Dir.chdir('test') do
132
+ puts 'Running tests'
133
+ system "adb uninstall #{package}.tests"
134
+ system "ant run-tests"
135
+ end
136
+ end
137
+
138
+ namespace :test do
139
+ task :quick => [:update_scripts, :update_test_scripts] do
140
+ Dir.chdir('test') do
141
+ puts 'Running quick tests'
142
+ system "ant run-tests-quick"
143
+ end
80
144
  end
81
145
  end
82
146
 
@@ -92,5 +156,6 @@ end
92
156
 
93
157
  def package() manifest.root.attribute('package') end
94
158
  def version() strings :version_name end
95
- def app_name() strings :app_name end
159
+ def app_name() strings :app_name end
160
+ def main_activity() manifest.root.elements['application'].elements['activity'].attributes['android:name'] end
96
161
  def build_project_name() @build_project_name ||= REXML::Document.new(File.read('build.xml')).elements['project'].attribute(:name).value end
@@ -9,7 +9,7 @@
9
9
  #
10
10
  #######################################################
11
11
 
12
- $RUBOTO_VERSION = 6
12
+ $RUBOTO_VERSION = 7
13
13
 
14
14
  def confirm_ruboto_version(required_version, exact=true)
15
15
  raise "requires $RUBOTO_VERSION=#{required_version} or greater, current version #{$RUBOTO_VERSION}" if $RUBOTO_VERSION < required_version and not exact
@@ -20,38 +20,15 @@ require 'java'
20
20
 
21
21
  $package_name = "THE_PACKAGE"
22
22
 
23
- %w(Activity Dialog BroadcastReceiver Service).map do |klass|
24
- java_import "org.ruboto.Ruboto#{klass}"
25
- end
26
-
27
- RUBOTO_CLASSES = [RubotoActivity, RubotoBroadcastReceiver, RubotoService]
28
- $init_methods = Hash.new 'create'
29
- $init_methods[RubotoBroadcastReceiver] = 'receive'
30
-
31
- java_import "android.app.Activity"
32
- java_import "android.content.Intent"
33
- java_import "android.os.Bundle"
34
-
35
- java_import "android.view.View"
36
- java_import "android.view.ViewGroup"
37
-
38
- java_import "android.widget.Toast"
39
-
40
- java_import "android.widget.ArrayAdapter"
41
- java_import "java.util.Arrays"
42
- java_import "java.util.ArrayList"
43
23
  java_import "android.R"
44
24
 
45
- java_import "android.util.Log"
46
-
47
25
  module Ruboto
48
26
  java_import "#{$package_name}.R"
49
27
  begin
50
28
  Id = JavaUtilities.get_proxy_class("#{$package_name}.R$id")
51
29
  rescue NameError
52
- Log.d "RUBOTO", "no R$id"
30
+ Java::android.util.Log.d "RUBOTO", "no R$id"
53
31
  end
54
-
55
32
  end
56
33
  AndroidIds = JavaUtilities.get_proxy_class("android.R$id")
57
34
 
@@ -60,7 +37,10 @@ AndroidIds = JavaUtilities.get_proxy_class("android.R$id")
60
37
  # Activity
61
38
  #
62
39
 
63
- class Activity
40
+ def setup_activity
41
+ java_import "android.app.Activity"
42
+
43
+ Activity.class_eval do
64
44
  def start_ruboto_dialog(remote_variable, &block)
65
45
  start_ruboto_activity(remote_variable, RubotoDialog, &block)
66
46
  end
@@ -68,13 +48,13 @@ class Activity
68
48
  def start_ruboto_activity(remote_variable, klass=RubotoActivity, &block)
69
49
  $activity_init_block = block
70
50
 
71
- if @initialized or not self.kind_of?(RubotoActivity)
72
- b = Bundle.new
51
+ if @initialized or self == $activity
52
+ b = Java::android.os.Bundle.new
73
53
  b.putString("Remote Variable", remote_variable)
74
54
  b.putBoolean("Define Remote Variable", true)
75
55
  b.putString("Initialize Script", "#{remote_variable}.initialize_activity")
76
56
 
77
- i = Intent.new
57
+ i = Java::android.content.Intent.new
78
58
  i.setClass self, klass.java_class
79
59
  i.putExtra("RubotoActivity Config", b)
80
60
 
@@ -91,13 +71,14 @@ class Activity
91
71
 
92
72
  #plugin
93
73
  def toast(text, duration=5000)
94
- Toast.makeText(self, text, duration).show
74
+ Java::android.widget.Toast.makeText(self, text, duration).show
95
75
  end
96
76
 
97
77
  #plugin
98
78
  def toast_result(result, success, failure, duration=5000)
99
79
  toast(result ? success : failure, duration)
100
80
  end
81
+ end
101
82
  end
102
83
 
103
84
  #############################################################################
@@ -220,9 +201,13 @@ def ruboto_configure_activity(klass)
220
201
 
221
202
  ruboto_allow_handlers(klass)
222
203
  end
223
- ruboto_configure_activity(RubotoActivity)
224
204
 
225
- RUBOTO_CLASSES.each do |klass|
205
+ #############################################################################
206
+ #
207
+ # Ruboto Set up for all app types (Activity, Service, BroadcastReceiver)
208
+ #
209
+
210
+ def ruboto_setup(klass, init_method="create")
226
211
  # Setup ability to handle callbacks
227
212
  ruboto_allow_handlers(klass)
228
213
 
@@ -233,7 +218,7 @@ RUBOTO_CLASSES.each do |klass|
233
218
  end
234
219
 
235
220
  eval %Q{
236
- def handle_#{$init_methods[klass]}(&block)
221
+ def handle_#{init_method}(&block)
237
222
  when_launched &block
238
223
  end
239
224
  }
@@ -266,6 +251,11 @@ def ruboto_import_widget(class_name, package_name="android.widget")
266
251
  rv
267
252
  end
268
253
  "
254
+
255
+ setup_list_view if class_name == :ListView
256
+ setup_button if class_name == :Button
257
+ setup_linear_layout if class_name == :LinearLayout
258
+ setup_relative_layout if class_name == :RelativeLayout
269
259
  end
270
260
 
271
261
  #############################################################################
@@ -273,62 +263,104 @@ end
273
263
  # Extend Common View Classes
274
264
  #
275
265
 
276
- # Need to load these two to extend classes
277
- ruboto_import_widgets :ListView, :Button
266
+ def setup_view
267
+ java_import "android.view.View"
268
+ java_import "android.view.ViewGroup"
278
269
 
279
- class View
280
- @@convert_params = {
281
- :wrap_content => ViewGroup::LayoutParams::WRAP_CONTENT,
282
- :fill_parent => ViewGroup::LayoutParams::FILL_PARENT,
283
- }
270
+ View.class_eval do
271
+ @@convert_constants ||= {}
272
+
273
+ def self.add_constant_conversion(from, to)
274
+ @@convert_constants[from] = to
275
+ end
276
+
277
+ def self.convert_constant(from)
278
+ @@convert_constants[from] or from
279
+ end
280
+
281
+ def self.setup_constant_conversion
282
+ (self.constants - self.superclass.constants).each do |i|
283
+ View.add_constant_conversion i.downcase.to_sym, self.const_get(i)
284
+ end
285
+ end
284
286
 
285
287
  def configure(context, params = {})
286
288
  if width = params.delete(:width)
287
- getLayoutParams.width = @@convert_params[width] or width
289
+ getLayoutParams.width = View.convert_constant(width)
288
290
  end
289
291
 
290
292
  if height = params.delete(:height)
291
- getLayoutParams.height = @@convert_params[height] or height
293
+ getLayoutParams.height = View.convert_constant(height)
292
294
  end
293
295
 
294
- params.each do |k, v|
295
- if v.is_a?(Array)
296
- self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) {$2.upcase}}", *v)
297
- else
298
- self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) {$2.upcase}}", v)
296
+ if layout = params.delete(:layout)
297
+ lp = getLayoutParams
298
+ layout.each do |k, v|
299
+ values = (v.is_a?(Array) ? v : [v]).map{|i| @@convert_constants[i] or i}
300
+ lp.send("#{k.to_s.gsub(/_([a-z])/) {$1.upcase}}", *values)
299
301
  end
300
302
  end
303
+
304
+ params.each do |k, v|
305
+ values = (v.is_a?(Array) ? v : [v]).map{|i| @@convert_constants[i] or i}
306
+ self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) {$2.upcase}}", *values)
307
+ end
301
308
  end
309
+ end
310
+
311
+ View.add_constant_conversion :wrap_content, ViewGroup::LayoutParams::WRAP_CONTENT
312
+ View.add_constant_conversion :fill_parent, ViewGroup::LayoutParams::FILL_PARENT
302
313
  end
303
314
 
304
- class ListView
305
- attr_reader :adapter, :adapter_list
315
+ #############################################################################
316
+ #
317
+ # Special widget setup
318
+ #
306
319
 
307
- def configure(context, params = {})
308
- if params.has_key? :list
309
- @adapter_list = ArrayList.new
310
- @adapter_list.addAll(params[:list])
311
- @adapter = ArrayAdapter.new(context, R::layout::simple_list_item_1, @adapter_list)
312
- setAdapter @adapter
313
- params.delete :list
320
+ def setup_linear_layout
321
+ LinearLayout.setup_constant_conversion
322
+ end
323
+
324
+ def setup_relative_layout
325
+ RelativeLayout.setup_constant_conversion
326
+ end
327
+
328
+ def setup_button
329
+ Button.class_eval do
330
+ def configure(context, params = {})
331
+ setOnClickListener(context)
332
+ super(context, params)
314
333
  end
315
- setOnItemClickListener(context)
316
- super(context, params)
317
334
  end
318
335
 
319
- def reload_list(list)
320
- @adapter_list.clear();
321
- @adapter_list.addAll(list)
322
- @adapter.notifyDataSetChanged
323
- invalidate
324
- end
336
+ ruboto_register_handler("org.ruboto.callbacks.RubotoOnClickListener", "click", Button, "setOnClickListener")
325
337
  end
326
338
 
327
- class Button
328
- def configure(context, params = {})
329
- setOnClickListener(context)
330
- super(context, params)
339
+ def setup_list_view
340
+ ListView.class_eval do
341
+ attr_reader :adapter, :adapter_list
342
+
343
+ def configure(context, params = {})
344
+ if params.has_key? :list
345
+ @adapter_list = Java::java.util.ArrayList.new
346
+ @adapter_list.addAll(params[:list])
347
+ @adapter = Java::android.widget.ArrayAdapter.new(context, R::layout::simple_list_item_1, @adapter_list)
348
+ setAdapter @adapter
349
+ params.delete :list
350
+ end
351
+ setOnItemClickListener(context)
352
+ super(context, params)
353
+ end
354
+
355
+ def reload_list(list)
356
+ @adapter_list.clear();
357
+ @adapter_list.addAll(list)
358
+ @adapter.notifyDataSetChanged
359
+ invalidate
360
+ end
331
361
  end
362
+
363
+ ruboto_register_handler("org.ruboto.callbacks.RubotoOnItemClickListener", "item_click", ListView, "setOnItemClickListener")
332
364
  end
333
365
 
334
366
  #############################################################################
@@ -373,9 +405,6 @@ def ruboto_register_handler(handler_class, unique_name, for_class, method_name)
373
405
  "
374
406
  end
375
407
 
376
- ruboto_register_handler("org.ruboto.callbacks.RubotoOnClickListener", "click", Button, "setOnClickListener")
377
- ruboto_register_handler("org.ruboto.callbacks.RubotoOnItemClickListener", "item_click", ListView, "setOnItemClickListener")
378
-
379
408
  #############################################################################
380
409
  #
381
410
  # RubotoPreferenceActivity Preference Generation
@@ -454,3 +483,27 @@ def setup_preferences
454
483
  @preferences_setup_complete = true
455
484
  end
456
485
 
486
+ #############################################################################
487
+ #############################################################################
488
+ #
489
+ # Final set up depending on globals
490
+ #
491
+
492
+ if $activity
493
+ java_import "org.ruboto.RubotoActivity"
494
+ setup_activity
495
+ ruboto_configure_activity(RubotoActivity)
496
+ ruboto_setup(RubotoActivity)
497
+ setup_view
498
+ end
499
+
500
+ if $service
501
+ java_import "org.ruboto.RubotoService"
502
+ ruboto_setup(RubotoService)
503
+ end
504
+
505
+ if $broadcast_receiver
506
+ java_import "org.ruboto.RubotoBroadcastReceiver"
507
+ ruboto_setup(RubotoBroadcastReceiver, "receive")
508
+ end
509
+