ruboto 0.5.4 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +9 -9
- data/README.md +2 -0
- data/Rakefile +71 -7
- data/assets/Rakefile +2 -407
- data/assets/libs/dexmaker20120305.jar +0 -0
- data/assets/rakelib/ruboto.rake +428 -0
- data/assets/samples/sample_broadcast_receiver.rb +7 -3
- data/assets/samples/sample_broadcast_receiver_test.rb +47 -1
- data/assets/src/RubotoActivity.java +6 -2
- data/assets/src/org/ruboto/EntryPointActivity.java +2 -2
- data/assets/src/org/ruboto/Script.java +91 -24
- data/assets/src/org/ruboto/test/ActivityTest.java +27 -24
- data/assets/src/org/ruboto/test/InstrumentationTestRunner.java +42 -8
- data/assets/src/ruboto/activity.rb +1 -1
- data/assets/src/ruboto/base.rb +17 -6
- data/assets/src/ruboto/generate.rb +458 -0
- data/assets/src/ruboto/legacy.rb +9 -12
- data/assets/src/ruboto/widget.rb +9 -1
- data/lib/java_class_gen/android_api.xml +1 -1
- data/lib/ruboto.rb +1 -2
- data/lib/ruboto/commands/base.rb +19 -4
- data/lib/ruboto/sdk_versions.rb +12 -0
- data/lib/ruboto/util/build.rb +10 -11
- data/lib/ruboto/util/update.rb +150 -51
- data/lib/ruboto/util/verify.rb +6 -4
- data/lib/ruboto/util/xml_element.rb +2 -2
- data/lib/ruboto/version.rb +1 -1
- data/test/activity/option_menu_activity.rb +5 -1
- data/test/activity/psych_activity.rb +11 -6
- data/test/activity/stack_activity_test.rb +13 -5
- data/test/app_test_methods.rb +4 -3
- data/test/broadcast_receiver_test.rb +86 -0
- data/test/minimal_app_test.rb +27 -19
- data/test/rake_test.rb +13 -2
- data/test/ruboto_gen_test.rb +17 -3
- data/test/ruboto_update_test.rb +24 -2
- data/test/service_test.rb +1 -1
- data/test/test_helper.rb +134 -62
- data/test/update_test_methods.rb +40 -14
- data/test/updated_example_test_methods.rb +41 -0
- 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
|
-
|
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
|
-
|
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
|
-
|
79
|
-
|
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
|
-
|
106
|
-
|
107
|
-
|
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
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
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
|
-
|
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
|
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
|
-
|
424
|
+
isDebugBuild = ((pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
|
380
425
|
} catch (NameNotFoundException e) {
|
381
|
-
|
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
|
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
|
-
|
526
|
-
|
527
|
-
|
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
|
-
|
531
|
-
|
532
|
-
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
Log.i(getClass().getName(), "
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
}
|
59
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
|