ruboto 0.5.4 → 0.6.0

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.
Files changed (41) hide show
  1. data/Gemfile.lock +9 -9
  2. data/README.md +2 -0
  3. data/Rakefile +71 -7
  4. data/assets/Rakefile +2 -407
  5. data/assets/libs/dexmaker20120305.jar +0 -0
  6. data/assets/rakelib/ruboto.rake +428 -0
  7. data/assets/samples/sample_broadcast_receiver.rb +7 -3
  8. data/assets/samples/sample_broadcast_receiver_test.rb +47 -1
  9. data/assets/src/RubotoActivity.java +6 -2
  10. data/assets/src/org/ruboto/EntryPointActivity.java +2 -2
  11. data/assets/src/org/ruboto/Script.java +91 -24
  12. data/assets/src/org/ruboto/test/ActivityTest.java +27 -24
  13. data/assets/src/org/ruboto/test/InstrumentationTestRunner.java +42 -8
  14. data/assets/src/ruboto/activity.rb +1 -1
  15. data/assets/src/ruboto/base.rb +17 -6
  16. data/assets/src/ruboto/generate.rb +458 -0
  17. data/assets/src/ruboto/legacy.rb +9 -12
  18. data/assets/src/ruboto/widget.rb +9 -1
  19. data/lib/java_class_gen/android_api.xml +1 -1
  20. data/lib/ruboto.rb +1 -2
  21. data/lib/ruboto/commands/base.rb +19 -4
  22. data/lib/ruboto/sdk_versions.rb +12 -0
  23. data/lib/ruboto/util/build.rb +10 -11
  24. data/lib/ruboto/util/update.rb +150 -51
  25. data/lib/ruboto/util/verify.rb +6 -4
  26. data/lib/ruboto/util/xml_element.rb +2 -2
  27. data/lib/ruboto/version.rb +1 -1
  28. data/test/activity/option_menu_activity.rb +5 -1
  29. data/test/activity/psych_activity.rb +11 -6
  30. data/test/activity/stack_activity_test.rb +13 -5
  31. data/test/app_test_methods.rb +4 -3
  32. data/test/broadcast_receiver_test.rb +86 -0
  33. data/test/minimal_app_test.rb +27 -19
  34. data/test/rake_test.rb +13 -2
  35. data/test/ruboto_gen_test.rb +17 -3
  36. data/test/ruboto_update_test.rb +24 -2
  37. data/test/service_test.rb +1 -1
  38. data/test/test_helper.rb +134 -62
  39. data/test/update_test_methods.rb +40 -14
  40. data/test/updated_example_test_methods.rb +41 -0
  41. metadata +12 -6
@@ -17,7 +17,7 @@ public class THE_RUBOTO_CLASS THE_ACTION THE_ANDROID_CLASS {
17
17
  private String scriptName;
18
18
  private String remoteVariable = null;
19
19
  private Object[] args;
20
- private Bundle configBundle;
20
+ private Bundle configBundle = null;
21
21
 
22
22
  THE_CONSTANTS
23
23
 
@@ -85,7 +85,7 @@ THE_CONSTANTS
85
85
  if (scriptName != null) {
86
86
  Script.setScriptFilename(getClass().getClassLoader().getResource(scriptName).getPath());
87
87
  Script.execute(new Script(scriptName).getContents());
88
- } else {
88
+ } else if (configBundle != null) {
89
89
  // TODO: Why doesn't this work?
90
90
  // Script.callMethod(this, "initialize_ruboto");
91
91
  Script.execute("$activity.initialize_ruboto");
@@ -99,6 +99,10 @@ THE_CONSTANTS
99
99
  }
100
100
  }
101
101
 
102
+ public boolean rubotoAttachable() {
103
+ return true;
104
+ }
105
+
102
106
  /****************************************************************************************
103
107
  *
104
108
  * Generated Methods
@@ -25,7 +25,7 @@ public class EntryPointActivity extends org.ruboto.RubotoActivity {
25
25
  private ProgressDialog loadingDialog;
26
26
  private boolean dialogCancelled = false;
27
27
  private BroadcastReceiver receiver;
28
- private boolean appStarted = false;
28
+ protected boolean appStarted = false;
29
29
 
30
30
  public void onCreate(Bundle bundle) {
31
31
  Log.d("RUBOTO", "onCreate: ");
@@ -154,7 +154,7 @@ public class EntryPointActivity extends org.ruboto.RubotoActivity {
154
154
  }
155
155
  }
156
156
 
157
- private void fireRubotoActivity() {
157
+ protected void fireRubotoActivity() {
158
158
  if(appStarted) return;
159
159
  appStarted = true;
160
160
  Log.i("RUBOTO", "Starting activity");
@@ -33,6 +33,8 @@ public class Script {
33
33
 
34
34
  private String name = null;
35
35
  private static Object ruby;
36
+ private static boolean isDebugBuild = false;
37
+ private static PrintStream output = null;
36
38
  private static boolean initialized = false;
37
39
 
38
40
  private static String localContextScope = "SINGLETON";
@@ -40,6 +42,7 @@ public class Script {
40
42
 
41
43
  public static final String TAG = "RUBOTO"; // for logging
42
44
  private static String JRUBY_VERSION;
45
+ private static String RUBOTO_CORE_VERSION_NAME;
43
46
 
44
47
  /*************************************************************************************************
45
48
  *
@@ -69,19 +72,29 @@ public class Script {
69
72
  return initialized;
70
73
  }
71
74
 
75
+ public static boolean usesPlatformApk() {
76
+ return RUBOTO_CORE_VERSION_NAME != null;
77
+ }
78
+
79
+ public static String getPlatformVersionName() {
80
+ return RUBOTO_CORE_VERSION_NAME;
81
+ }
82
+
72
83
  public static synchronized boolean setUpJRuby(Context appContext) {
73
- return setUpJRuby(appContext, System.out);
84
+ return setUpJRuby(appContext, output == null ? System.out : output);
74
85
  }
75
86
 
76
87
  public static synchronized boolean setUpJRuby(Context appContext, PrintStream out) {
77
88
  if (!initialized) {
78
- Log.d(TAG, "Setting up JRuby runtime");
79
- System.setProperty("jruby.bytecode.version", "1.5");
89
+ setDebugBuild(appContext);
90
+ Log.d(TAG, "Setting up JRuby runtime (" + (isDebugBuild ? "DEBUG" : "RELEASE") + ")");
91
+ System.setProperty("jruby.bytecode.version", "1.6");
80
92
  System.setProperty("jruby.interfaces.useProxy", "true");
81
93
  System.setProperty("jruby.management.enabled", "false");
82
94
  System.setProperty("jruby.objectspace.enabled", "false");
83
95
  System.setProperty("jruby.thread.pooling", "true");
84
96
  System.setProperty("jruby.native.enabled", "false");
97
+ // System.setProperty("jruby.compat.version", "RUBY1_8"); // RUBY1_9 is the default
85
98
 
86
99
  // Uncomment these to debug Ruby source loading
87
100
  // System.setProperty("jruby.debug.loadService", "true");
@@ -102,9 +115,14 @@ public class Script {
102
115
  } catch (ClassNotFoundException e1) {
103
116
  String packageName = "org.ruboto.core";
104
117
  try {
105
- apkName = appContext.getPackageManager().getApplicationInfo(packageName, 0).sourceDir;
106
- } catch (PackageManager.NameNotFoundException e) {
107
- System.out.println("JRuby not found");
118
+ PackageInfo pkgInfo = appContext.getPackageManager().getPackageInfo(packageName, 0);
119
+ apkName = pkgInfo.applicationInfo.sourceDir;
120
+ RUBOTO_CORE_VERSION_NAME = pkgInfo.versionName;
121
+ } catch (PackageManager.NameNotFoundException e2) {
122
+ out.println("JRuby not found in local APK:");
123
+ e1.printStackTrace(out);
124
+ out.println("JRuby not found in platform APK:");
125
+ e2.printStackTrace(out);
108
126
  return false;
109
127
  }
110
128
 
@@ -169,10 +187,10 @@ public class Script {
169
187
  callScriptingContainerMethod(Void.class, "setCurrentDirectory", defaultCurrentDir);
170
188
 
171
189
  if (out != null) {
172
- Method setOutputMethod = ruby.getClass().getMethod("setOutput", PrintStream.class);
173
- setOutputMethod.invoke(ruby, out);
174
- Method setErrorMethod = ruby.getClass().getMethod("setError", PrintStream.class);
175
- setErrorMethod.invoke(ruby, out);
190
+ output = out;
191
+ setOutputStream(out);
192
+ } else if (output != null) {
193
+ setOutputStream(output);
176
194
  }
177
195
 
178
196
  String jrubyHome = "file:" + apkName + "!";
@@ -204,6 +222,29 @@ public class Script {
204
222
  return initialized;
205
223
  }
206
224
 
225
+ public static void setOutputStream(PrintStream out) {
226
+ if (ruby == null) {
227
+ output = out;
228
+ } else {
229
+ try {
230
+ Method setOutputMethod = ruby.getClass().getMethod("setOutput", PrintStream.class);
231
+ setOutputMethod.invoke(ruby, out);
232
+ Method setErrorMethod = ruby.getClass().getMethod("setError", PrintStream.class);
233
+ setErrorMethod.invoke(ruby, out);
234
+ } catch (IllegalArgumentException e) {
235
+ handleInitException(e);
236
+ } catch (SecurityException e) {
237
+ handleInitException(e);
238
+ } catch (IllegalAccessException e) {
239
+ handleInitException(e);
240
+ } catch (InvocationTargetException e) {
241
+ handleInitException(e);
242
+ } catch (NoSuchMethodException e) {
243
+ handleInitException(e);
244
+ }
245
+ }
246
+ }
247
+
207
248
  private static void handleInitException(Exception e) {
208
249
  Log.e(TAG, "Exception starting JRuby");
209
250
  Log.e(TAG, e.getMessage() != null ? e.getMessage() : e.getClass().getName());
@@ -252,7 +293,11 @@ public class Script {
252
293
  } catch (IllegalAccessException iae) {
253
294
  throw new RuntimeException(iae);
254
295
  } catch (java.lang.reflect.InvocationTargetException ite) {
255
- throw ((RuntimeException) ite.getCause());
296
+ if (isDebugBuild) {
297
+ throw ((RuntimeException) ite.getCause());
298
+ } else {
299
+ return null;
300
+ }
256
301
  }
257
302
  }
258
303
 
@@ -315,7 +360,7 @@ public class Script {
315
360
  }
316
361
 
317
362
  private static List<String> getLoadPath() {
318
- return callScriptingContainerMethod(List.class, "getLoadPaths");
363
+ return (List<String>)callScriptingContainerMethod(List.class, "getLoadPaths");
319
364
  }
320
365
 
321
366
  public static Boolean configDir(String scriptsDir) {
@@ -371,21 +416,20 @@ public class Script {
371
416
  }
372
417
  }
373
418
 
374
- private static boolean isDebugBuild(Context context) {
419
+ private static void setDebugBuild(Context context) {
375
420
  PackageManager pm = context.getPackageManager();
376
421
  PackageInfo pi;
377
422
  try {
378
423
  pi = pm.getPackageInfo(context.getPackageName(), 0);
379
- return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
424
+ isDebugBuild = ((pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
380
425
  } catch (NameNotFoundException e) {
381
- return false;
426
+ isDebugBuild = false;
382
427
  }
383
-
384
428
  }
385
429
 
386
430
  private static String scriptsDirName(Context context) {
387
431
  File storageDir = null;
388
- if (isDebugBuild(context)) {
432
+ if (isDebugBuild) {
389
433
 
390
434
  // FIXME(uwe): Simplify this as soon as we drop support for android-7 or JRuby 1.5.6 or JRuby 1.6.2
391
435
  Log.i(TAG, "JRuby VERSION: " + JRUBY_VERSION);
@@ -474,7 +518,7 @@ public class Script {
474
518
  */
475
519
 
476
520
  public static String getScriptFilename() {
477
- return callScriptingContainerMethod(String.class, "getScriptFilename");
521
+ return (String)callScriptingContainerMethod(String.class, "getScriptFilename");
478
522
  }
479
523
 
480
524
  public static void setScriptFilename(String name) {
@@ -496,6 +540,9 @@ public class Script {
496
540
  throw new RuntimeException(iae);
497
541
  } catch (java.lang.reflect.InvocationTargetException ite) {
498
542
  printStackTrace(ite);
543
+ if (isDebugBuild) {
544
+ throw new RuntimeException(ite);
545
+ }
499
546
  }
500
547
  }
501
548
 
@@ -522,14 +569,34 @@ public class Script {
522
569
  return null;
523
570
  }
524
571
 
525
- public static <T> T callMethod(Object receiver, String methodName,
526
- Object arg, Class<T> returnType) {
527
- return callMethod(receiver, methodName, new Object[]{arg}, returnType);
572
+ @SuppressWarnings("unchecked")
573
+ public static <T> T callMethod(Object receiver, String methodName, Object arg, Class<T> returnType) {
574
+ try {
575
+ Method callMethodMethod = ruby.getClass().getMethod("callMethod", Object.class, String.class, Object.class, Class.class);
576
+ return (T) callMethodMethod.invoke(ruby, receiver, methodName, arg, returnType);
577
+ } catch (NoSuchMethodException nsme) {
578
+ throw new RuntimeException(nsme);
579
+ } catch (IllegalAccessException iae) {
580
+ throw new RuntimeException(iae);
581
+ } catch (java.lang.reflect.InvocationTargetException ite) {
582
+ printStackTrace(ite);
583
+ }
584
+ return null;
528
585
  }
529
586
 
530
- public static <T> T callMethod(Object receiver, String methodName,
531
- Class<T> returnType) {
532
- return callMethod(receiver, methodName, new Object[]{}, returnType);
587
+ @SuppressWarnings("unchecked")
588
+ public static <T> T callMethod(Object receiver, String methodName, Class<T> returnType) {
589
+ try {
590
+ Method callMethodMethod = ruby.getClass().getMethod("callMethod", Object.class, String.class, Class.class);
591
+ return (T) callMethodMethod.invoke(ruby, receiver, methodName, returnType);
592
+ } catch (NoSuchMethodException nsme) {
593
+ throw new RuntimeException(nsme);
594
+ } catch (IllegalAccessException iae) {
595
+ throw new RuntimeException(iae);
596
+ } catch (java.lang.reflect.InvocationTargetException ite) {
597
+ printStackTrace(ite);
598
+ }
599
+ return null;
533
600
  }
534
601
 
535
602
  private static void printStackTrace(Throwable t) {
@@ -19,44 +19,47 @@ public class ActivityTest extends ActivityInstrumentationTestCase2 {
19
19
  private final Object setup;
20
20
  private final Object block;
21
21
  private final String filename;
22
+ private final boolean onUiThread;
22
23
 
23
- public ActivityTest(Class activityClass, String filename, Object setup, String name, Object block) {
24
+ public ActivityTest(Class activityClass, String filename, Object setup, String name, boolean onUiThread, Object block) {
24
25
  super(activityClass.getPackage().getName(), activityClass);
25
26
  this.filename = filename;
26
27
  this.setup = setup;
27
28
  setName(filename + "#" + name);
29
+ this.onUiThread = onUiThread;
28
30
  this.block = block;
29
31
  Log.i(getClass().getName(), "Instance: " + getName());
30
32
  }
31
33
 
32
34
  public void runTest() throws Exception {
33
- Log.i(getClass().getName(), "runTest");
34
- Log.i(getClass().getName(), "runTest: " + getName());
35
- if (Script.setUpJRuby(getActivity())) {
36
- Log.i(getClass().getName(), "ruby ok");
37
- try {
38
- final Activity activity = getActivity();
39
- Log.i(getClass().getName(), "activity ok");
40
- runTestOnUiThread(new Runnable() {
41
- public void run() {
42
- String oldFile = Script.getScriptFilename();
35
+ try {
36
+ Log.i(getClass().getName(), "runTest: " + getName());
37
+ final Activity activity = getActivity();
38
+ Log.i(getClass().getName(), "Activity OK");
39
+ Runnable testRunnable = new Runnable() {
40
+ public void run() {
41
+ String oldFile = Script.getScriptFilename();
43
42
 
44
- Log.i(getClass().getName(), "calling setup");
45
- Script.setScriptFilename(filename);
46
- Script.callMethod(setup, "call", activity);
47
- Log.i(getClass().getName(), "setup ok");
43
+ Log.i(getClass().getName(), "calling setup");
44
+ Script.setScriptFilename(filename);
45
+ Script.callMethod(setup, "call", activity);
46
+ Log.i(getClass().getName(), "setup ok");
48
47
 
49
- Script.setScriptFilename(filename);
50
- Script.callMethod(block, "call", activity);
51
- Script.setScriptFilename(oldFile);
52
- }
53
- });
54
- } catch (Throwable t) {
55
- throw new AssertionFailedError(t.getMessage() != null ? t.getMessage() : t.getClass().getName());
48
+ Script.setScriptFilename(filename);
49
+ Script.callMethod(block, "call", activity);
50
+ Script.setScriptFilename(oldFile);
51
+ }
52
+ };
53
+ if (onUiThread) {
54
+ runTestOnUiThread(testRunnable);
55
+ } else {
56
+ testRunnable.run();
56
57
  }
57
58
  Log.i(getClass().getName(), "runTest ok");
58
- } else {
59
- throw new AssertionFailedError("Ruboto Core platform is missing.");
59
+ } catch (Throwable t) {
60
+ AssertionFailedError afe = new AssertionFailedError("Exception running test.");
61
+ afe.initCause(t);
62
+ throw afe;
60
63
  }
61
64
  }
62
65
 
@@ -15,10 +15,12 @@ import java.net.URLDecoder;
15
15
  import java.util.ArrayList;
16
16
  import java.util.Arrays;
17
17
  import java.util.Collections;
18
+ import java.util.concurrent.atomic.AtomicBoolean;
18
19
  import java.util.Enumeration;
19
20
  import java.util.jar.JarFile;
20
21
  import java.util.jar.JarEntry;
21
22
  import java.util.List;
23
+ import java.util.Map;
22
24
  import junit.framework.Test;
23
25
  import junit.framework.TestCase;
24
26
  import junit.framework.TestSuite;
@@ -34,15 +36,37 @@ public class InstrumentationTestRunner extends android.test.InstrumentationTestR
34
36
  public TestSuite getAllTests() {
35
37
  Log.i(getClass().getName(), "Finding test scripts");
36
38
  suite = new TestSuite("Sweet");
39
+ String loadStep = "Setup JRuby";
37
40
 
38
41
  try {
39
- if (Script.setUpJRuby(getTargetContext())) {
42
+ final AtomicBoolean JRubyLoadedOk = new AtomicBoolean();
43
+
44
+ // TODO(uwe): Running with large stack is currently only needed when running with JRuby 1.7.0 and android-10
45
+ // TODO(uwe): Simplify when we stop support for JRuby 1.7.0 or android-10
46
+ Thread t = new Thread(null, new Runnable() {
47
+ public void run() {
48
+ JRubyLoadedOk.set(Script.setUpJRuby(getTargetContext()));
49
+ }
50
+ }, "Setup JRuby from instrumentation test runner", 64 * 1024);
51
+ try {
52
+ t.start();
53
+ t.join();
54
+ } catch(InterruptedException ie) {
55
+ Thread.currentThread().interrupt();
56
+ throw new RuntimeException("Interrupted starting JRuby", ie);
57
+ }
58
+ // TODO end
59
+
60
+ if (JRubyLoadedOk.get()) {
61
+ loadStep = "Setup global variables";
40
62
  Script.defineGlobalVariable("$runner", this);
41
63
  Script.defineGlobalVariable("$test", this);
42
64
  Script.defineGlobalVariable("$suite", suite);
43
65
 
66
+ loadStep = "Load test helper";
44
67
  loadScript("test_helper.rb");
45
68
 
69
+ loadStep = "Get app test source dir";
46
70
  String test_apk_path = getContext().getPackageManager().getApplicationInfo(getContext().getPackageName(), 0).sourceDir;
47
71
  JarFile jar = new JarFile(test_apk_path);
48
72
  Enumeration<JarEntry> entries = jar.entries();
@@ -53,17 +77,18 @@ public class InstrumentationTestRunner extends android.test.InstrumentationTestR
53
77
  continue;
54
78
  }
55
79
  if (name.equals("test_helper.rb")) continue;
80
+ loadStep = "Load " + name;
56
81
  loadScript(name);
57
82
  }
58
83
  } else {
59
- addError(suite, new RuntimeException("Ruboto Core platform is missing"));
84
+ addError(suite, loadStep, new RuntimeException("Ruboto Core platform is missing"));
60
85
  }
61
86
  } catch (android.content.pm.PackageManager.NameNotFoundException e) {
62
- addError(suite, e);
87
+ addError(suite, loadStep, e);
63
88
  } catch (IOException e) {
64
- addError(suite, e);
89
+ addError(suite, loadStep, e);
65
90
  } catch (RuntimeException e) {
66
- addError(suite, e);
91
+ addError(suite, loadStep, e);
67
92
  }
68
93
  return suite;
69
94
  }
@@ -77,18 +102,27 @@ public class InstrumentationTestRunner extends android.test.InstrumentationTestR
77
102
  }
78
103
 
79
104
  public void test(String name, Object block) {
105
+ test(name, null, block);
106
+ }
107
+
108
+ public void test(String name, Map options, Object block) {
109
+ // FIXME(uwe): Remove when we stop supporting Android 2.2
80
110
  if (android.os.Build.VERSION.SDK_INT <= 8) {
81
111
  name ="runTest";
82
112
  }
83
- Test test = new ActivityTest(activityClass, Script.getScriptFilename(), setup, name, block);
113
+ // FIXME end
114
+
115
+ boolean runOnUiThread = options == null || options.get("ui") == "true";
116
+
117
+ Test test = new ActivityTest(activityClass, Script.getScriptFilename(), setup, name, runOnUiThread, block);
84
118
  suite.addTest(test);
85
119
  Log.d(getClass().getName(), "Made test instance: " + test);
86
120
  }
87
121
 
88
- private void addError(TestSuite suite, Throwable t) {
122
+ private void addError(TestSuite suite, String loadStep, Throwable t) {
89
123
  Throwable cause = t;
90
124
  while(cause != null) {
91
- Log.e(getClass().getName(), "Exception loading tests: " + cause);
125
+ Log.e(getClass().getName(), "Exception loading tests (" + loadStep + "): " + cause);
92
126
  t = cause;
93
127
  cause = t.getCause();
94
128
  }
@@ -35,7 +35,7 @@ module Ruboto
35
35
  $context_init_block = block
36
36
  $new_context_global = global_variable_name
37
37
 
38
- if @initialized or (self == $activity && !$activity.kind_of?(RubotoActivity))
38
+ if @initialized or (self == $activity && !$activity.rubotoAttachable)
39
39
  b = Java::android.os.Bundle.new
40
40
  b.putInt("Theme", theme) if theme
41
41