ruboto-core 0.0.2 → 0.0.3
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.
- data/Gemfile +4 -0
- data/Gemfile.lock +16 -0
- data/README.md +65 -3
- data/Rakefile +1 -135
- data/assets/Rakefile +2 -0
- data/assets/assets/scripts/ruboto.rb +243 -97
- data/assets/src/InheritingClass.java +28 -0
- data/assets/src/RubotoActivity.java +122 -0
- data/assets/src/RubotoBroadcastReceiver.java +77 -0
- data/assets/src/RubotoService.java +75 -0
- data/bin/ruboto +732 -44
- data/lib/java_class_gen/android_api.xml +1 -0
- metadata +11 -11
- data/assets/src/org/ruboto/RubotoActivity.java +0 -1406
- data/assets/src/org/ruboto/RubotoBroadcastReceiver.java +0 -126
- data/assets/src/org/ruboto/RubotoService.java +0 -233
- data/assets/src/org/ruboto/RubotoView.java +0 -30
- data/lib/java_class_gen/RubotoClass.java.erb +0 -197
- data/lib/java_class_gen/callback_reflection.rb +0 -109
- data/lib/java_class_gen/interfaces.txt +0 -1
@@ -0,0 +1,28 @@
|
|
1
|
+
package THE_PACKAGE;
|
2
|
+
|
3
|
+
import org.jruby.Ruby;
|
4
|
+
import org.jruby.javasupport.util.RuntimeHelpers;
|
5
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
6
|
+
import org.jruby.javasupport.JavaUtil;
|
7
|
+
import org.jruby.exceptions.RaiseException;
|
8
|
+
import org.ruboto.Script;
|
9
|
+
|
10
|
+
public class THE_RUBOTO_CLASS THE_ACTION THE_ANDROID_CLASS {
|
11
|
+
private Ruby __ruby__;
|
12
|
+
|
13
|
+
THE_CONSTANTS
|
14
|
+
private IRubyObject[] callbackProcs = new IRubyObject[CONSTANTS_COUNT];
|
15
|
+
|
16
|
+
THE_CONSTRUCTORS
|
17
|
+
|
18
|
+
private Ruby getRuby() {
|
19
|
+
if (__ruby__ == null) __ruby__ = Script.getRuby();
|
20
|
+
return __ruby__;
|
21
|
+
}
|
22
|
+
|
23
|
+
public void setCallbackProc(int id, IRubyObject obj) {
|
24
|
+
callbackProcs[id] = obj;
|
25
|
+
}
|
26
|
+
|
27
|
+
THE_METHODS
|
28
|
+
}
|
@@ -0,0 +1,122 @@
|
|
1
|
+
package THE_PACKAGE;
|
2
|
+
|
3
|
+
import org.jruby.Ruby;
|
4
|
+
import org.jruby.javasupport.util.RuntimeHelpers;
|
5
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
6
|
+
import org.jruby.javasupport.JavaUtil;
|
7
|
+
import org.jruby.exceptions.RaiseException;
|
8
|
+
import org.ruboto.Script;
|
9
|
+
import java.io.IOException;
|
10
|
+
import android.app.ProgressDialog;
|
11
|
+
import android.os.Handler;
|
12
|
+
|
13
|
+
public class THE_RUBOTO_CLASS THE_ACTION THE_ANDROID_CLASS {
|
14
|
+
private Ruby __ruby__;
|
15
|
+
private String scriptName;
|
16
|
+
private String remoteVariable = "";
|
17
|
+
public Object[] args;
|
18
|
+
private ProgressDialog loadingDialog;
|
19
|
+
|
20
|
+
THE_CONSTANTS
|
21
|
+
private IRubyObject[] callbackProcs = new IRubyObject[CONSTANTS_COUNT];
|
22
|
+
|
23
|
+
private Ruby getRuby() {
|
24
|
+
if (__ruby__ == null) __ruby__ = Script.getRuby();
|
25
|
+
|
26
|
+
if (__ruby__ == null) {
|
27
|
+
Script.setUpJRuby(null);
|
28
|
+
__ruby__ = Script.getRuby();
|
29
|
+
}
|
30
|
+
|
31
|
+
return __ruby__;
|
32
|
+
}
|
33
|
+
|
34
|
+
public void setCallbackProc(int id, IRubyObject obj) {
|
35
|
+
callbackProcs[id] = obj;
|
36
|
+
}
|
37
|
+
|
38
|
+
public THE_RUBOTO_CLASS setRemoteVariable(String var) {
|
39
|
+
remoteVariable = ((var == null) ? "" : (var + "."));
|
40
|
+
return this;
|
41
|
+
}
|
42
|
+
|
43
|
+
public void setScriptName(String name){
|
44
|
+
scriptName = name;
|
45
|
+
}
|
46
|
+
|
47
|
+
/****************************************************************************************
|
48
|
+
*
|
49
|
+
* Activity Lifecycle: onCreate
|
50
|
+
*/
|
51
|
+
|
52
|
+
@Override
|
53
|
+
public void onCreate(android.os.Bundle arg0) {
|
54
|
+
args = new Object[1];
|
55
|
+
args[0] = arg0;
|
56
|
+
|
57
|
+
super.onCreate(arg0);
|
58
|
+
|
59
|
+
if (Script.getRuby() != null) {
|
60
|
+
finishCreate();
|
61
|
+
} else {
|
62
|
+
loadingThread.start();
|
63
|
+
loadingDialog = ProgressDialog.show(this, null, "Loading...", true, false);
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
private final Handler loadingHandler = new Handler();
|
68
|
+
|
69
|
+
private final Thread loadingThread = new Thread() {
|
70
|
+
public void run(){
|
71
|
+
Script.setUpJRuby(null);
|
72
|
+
loadingHandler.post(loadingComplete);
|
73
|
+
}
|
74
|
+
};
|
75
|
+
|
76
|
+
private final Runnable loadingComplete = new Runnable(){
|
77
|
+
public void run(){
|
78
|
+
loadingDialog.dismiss();
|
79
|
+
finishCreate();
|
80
|
+
onStart();
|
81
|
+
onResume();
|
82
|
+
}
|
83
|
+
};
|
84
|
+
|
85
|
+
private void finishCreate() {
|
86
|
+
Script.copyScriptsIfNeeded(getFilesDir().getAbsolutePath() + "/scripts", getAssets());
|
87
|
+
|
88
|
+
getRuby();
|
89
|
+
|
90
|
+
Script.defineGlobalVariable("$activity", this);
|
91
|
+
Script.defineGlobalVariable("$bundle", args[0]);
|
92
|
+
|
93
|
+
android.os.Bundle configBundle = getIntent().getBundleExtra("RubotoActivity Config");
|
94
|
+
|
95
|
+
if (configBundle != null) {
|
96
|
+
setRemoteVariable(configBundle.getString("Remote Variable"));
|
97
|
+
if (configBundle.getBoolean("Define Remote Variable")) {
|
98
|
+
Script.defineGlobalVariable(configBundle.getString("Remote Variable"), this);
|
99
|
+
setRemoteVariable(configBundle.getString("Remote Variable"));
|
100
|
+
}
|
101
|
+
if (configBundle.getString("Initialize Script") != null) {
|
102
|
+
Script.execute(configBundle.getString("Initialize Script"));
|
103
|
+
}
|
104
|
+
Script.execute(remoteVariable + "on_create($bundle)");
|
105
|
+
} else {
|
106
|
+
try {
|
107
|
+
new Script(scriptName).execute();
|
108
|
+
} catch(IOException e){
|
109
|
+
e.printStackTrace();
|
110
|
+
ProgressDialog.show(this, "Script failed", "Something bad happened", true, true);
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
/****************************************************************************************
|
116
|
+
*
|
117
|
+
* Generated Methods
|
118
|
+
*/
|
119
|
+
|
120
|
+
THE_METHODS
|
121
|
+
}
|
122
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
package THE_PACKAGE;
|
2
|
+
|
3
|
+
import org.jruby.Ruby;
|
4
|
+
import org.jruby.javasupport.util.RuntimeHelpers;
|
5
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
6
|
+
import org.jruby.javasupport.JavaUtil;
|
7
|
+
import org.jruby.exceptions.RaiseException;
|
8
|
+
import org.ruboto.Script;
|
9
|
+
import java.io.IOException;
|
10
|
+
import android.app.ProgressDialog;
|
11
|
+
|
12
|
+
public abstract class THE_RUBOTO_CLASS THE_ACTION THE_ANDROID_CLASS {
|
13
|
+
private Ruby __ruby__;
|
14
|
+
private String scriptName;
|
15
|
+
private String remoteVariable = "";
|
16
|
+
public Object[] args;
|
17
|
+
|
18
|
+
THE_CONSTANTS
|
19
|
+
private IRubyObject[] callbackProcs = new IRubyObject[CONSTANTS_COUNT];
|
20
|
+
|
21
|
+
private Ruby getRuby() {
|
22
|
+
if (__ruby__ == null) __ruby__ = Script.getRuby();
|
23
|
+
|
24
|
+
if (__ruby__ == null) {
|
25
|
+
Script.setUpJRuby(null);
|
26
|
+
__ruby__ = Script.getRuby();
|
27
|
+
}
|
28
|
+
|
29
|
+
return __ruby__;
|
30
|
+
}
|
31
|
+
|
32
|
+
public void setCallbackProc(int id, IRubyObject obj) {
|
33
|
+
callbackProcs[id] = obj;
|
34
|
+
}
|
35
|
+
|
36
|
+
public THE_RUBOTO_CLASS setRemoteVariable(String var) {
|
37
|
+
remoteVariable = ((var == null) ? "" : (var + "."));
|
38
|
+
return this;
|
39
|
+
}
|
40
|
+
|
41
|
+
public void setScriptName(String name){
|
42
|
+
scriptName = name;
|
43
|
+
}
|
44
|
+
|
45
|
+
/****************************************************************************************
|
46
|
+
*
|
47
|
+
* Activity Lifecycle: onCreate
|
48
|
+
*/
|
49
|
+
|
50
|
+
@Override
|
51
|
+
public void onReceive(android.content.Context arg0, android.content.Intent arg1) {
|
52
|
+
args = new Object[2];
|
53
|
+
args[0] = arg0;
|
54
|
+
args[1] = arg1;
|
55
|
+
|
56
|
+
getRuby();
|
57
|
+
|
58
|
+
Script.defineGlobalVariable("$broadcast_receiver", this);
|
59
|
+
Script.defineGlobalVariable("$broadcast_context", arg0);
|
60
|
+
Script.defineGlobalVariable("$broadcast_intent", arg1);
|
61
|
+
|
62
|
+
try {
|
63
|
+
new Script(scriptName).execute();
|
64
|
+
} catch(IOException e) {
|
65
|
+
e.printStackTrace();
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
/****************************************************************************************
|
70
|
+
*
|
71
|
+
* Generated Methods
|
72
|
+
*/
|
73
|
+
|
74
|
+
THE_METHODS
|
75
|
+
}
|
76
|
+
|
77
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
package THE_PACKAGE;
|
2
|
+
|
3
|
+
import org.jruby.Ruby;
|
4
|
+
import org.jruby.javasupport.util.RuntimeHelpers;
|
5
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
6
|
+
import org.jruby.javasupport.JavaUtil;
|
7
|
+
import org.jruby.exceptions.RaiseException;
|
8
|
+
import org.ruboto.Script;
|
9
|
+
import java.io.IOException;
|
10
|
+
import android.app.ProgressDialog;
|
11
|
+
|
12
|
+
public abstract class THE_RUBOTO_CLASS THE_ACTION THE_ANDROID_CLASS {
|
13
|
+
private Ruby __ruby__;
|
14
|
+
private String scriptName;
|
15
|
+
private String remoteVariable = "";
|
16
|
+
public Object[] args;
|
17
|
+
|
18
|
+
THE_CONSTANTS
|
19
|
+
private IRubyObject[] callbackProcs = new IRubyObject[CONSTANTS_COUNT];
|
20
|
+
|
21
|
+
private Ruby getRuby() {
|
22
|
+
if (__ruby__ == null) __ruby__ = Script.getRuby();
|
23
|
+
|
24
|
+
if (__ruby__ == null) {
|
25
|
+
Script.setUpJRuby(null);
|
26
|
+
__ruby__ = Script.getRuby();
|
27
|
+
}
|
28
|
+
|
29
|
+
return __ruby__;
|
30
|
+
}
|
31
|
+
|
32
|
+
public void setCallbackProc(int id, IRubyObject obj) {
|
33
|
+
callbackProcs[id] = obj;
|
34
|
+
}
|
35
|
+
|
36
|
+
public THE_RUBOTO_CLASS setRemoteVariable(String var) {
|
37
|
+
remoteVariable = ((var == null) ? "" : (var + "."));
|
38
|
+
return this;
|
39
|
+
}
|
40
|
+
|
41
|
+
public void setScriptName(String name){
|
42
|
+
scriptName = name;
|
43
|
+
}
|
44
|
+
|
45
|
+
/****************************************************************************************
|
46
|
+
*
|
47
|
+
* Activity Lifecycle: onCreate
|
48
|
+
*/
|
49
|
+
|
50
|
+
@Override
|
51
|
+
public void onCreate() {
|
52
|
+
args = new Object[0];
|
53
|
+
|
54
|
+
super.onCreate();
|
55
|
+
|
56
|
+
getRuby();
|
57
|
+
|
58
|
+
Script.defineGlobalVariable("$service", this);
|
59
|
+
|
60
|
+
try {
|
61
|
+
new Script(scriptName).execute();
|
62
|
+
} catch(IOException e) {
|
63
|
+
e.printStackTrace();
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
/****************************************************************************************
|
68
|
+
*
|
69
|
+
* Generated Methods
|
70
|
+
*/
|
71
|
+
|
72
|
+
THE_METHODS
|
73
|
+
}
|
74
|
+
|
75
|
+
|
data/bin/ruboto
CHANGED
@@ -26,6 +26,7 @@ module Main
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
$gem_root = File.expand_path(__FILE__+ "/../..")
|
29
30
|
$assets = File.expand_path(__FILE__ + "/../../assets")
|
30
31
|
|
31
32
|
class AssetCopier
|
@@ -45,6 +46,564 @@ class AssetCopier
|
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
49
|
+
###########################################################################
|
50
|
+
#
|
51
|
+
# log_action: put text to stdout around the execution of a block
|
52
|
+
#
|
53
|
+
|
54
|
+
def log_action(initial_text, final_text="Done.", &block)
|
55
|
+
$stdout.sync = true
|
56
|
+
print initial_text, "..."
|
57
|
+
yield
|
58
|
+
puts final_text
|
59
|
+
end
|
60
|
+
|
61
|
+
###########################################################################
|
62
|
+
#
|
63
|
+
# XMLElement:
|
64
|
+
# Extends Hash to simulate a REXML::Element (but much faster) and provides
|
65
|
+
# information in the necessary format to generate Java code.
|
66
|
+
#
|
67
|
+
|
68
|
+
class XMLElement < Hash
|
69
|
+
def root
|
70
|
+
$api
|
71
|
+
end
|
72
|
+
|
73
|
+
def name
|
74
|
+
self["name"]
|
75
|
+
end
|
76
|
+
|
77
|
+
def attribute(name)
|
78
|
+
self["values"][name]
|
79
|
+
end
|
80
|
+
|
81
|
+
def add_element(name, attributes)
|
82
|
+
new_element = XMLElement.new
|
83
|
+
new_element["name"] = name
|
84
|
+
new_element["values"] = attributes
|
85
|
+
|
86
|
+
self[name] = [] unless self[name]
|
87
|
+
self[name] << new_element
|
88
|
+
|
89
|
+
new_element
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_elements(name)
|
93
|
+
self[name] or []
|
94
|
+
end
|
95
|
+
|
96
|
+
def find_class_or_interface(klass, a_type)
|
97
|
+
abort "ERROR: Can't parse package from #{klass}" unless klass.match(/([a-z.]+)\.([A-Z][A-Za-z.]+)/)
|
98
|
+
package = self["package"].find{|i| i.attribute("name") == $1}
|
99
|
+
abort "ERROR: Can't find package #{$1}" unless package
|
100
|
+
if a_type == "either"
|
101
|
+
package["class"].find{|i| i.attribute("name") == $2} or package["interface"].find{|i| i.attribute("name") == $2}
|
102
|
+
else
|
103
|
+
package[a_type].find{|i| i.attribute("name") == $2}
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def find_class(package_and_class)
|
108
|
+
find_class_or_interface(package_and_class, "class")
|
109
|
+
end
|
110
|
+
|
111
|
+
def find_interface(package_and_interface)
|
112
|
+
find_class_or_interface(package_and_interface, "interface")
|
113
|
+
end
|
114
|
+
|
115
|
+
def all_methods(method_base="all", method_include="", method_exclude="", implements="")
|
116
|
+
# get all the methogs
|
117
|
+
all_methods = get_elements("method")
|
118
|
+
|
119
|
+
# establish the base set of methods
|
120
|
+
working_methods = case method_base
|
121
|
+
when "all"
|
122
|
+
all_methods
|
123
|
+
when "none"
|
124
|
+
[]
|
125
|
+
when "abstract"
|
126
|
+
all_methods.select{|i| i.attribute("abstract") == "true"}
|
127
|
+
when "on"
|
128
|
+
all_methods.select{|i| i.attribute("name").match(/^on[A-Z]/)}
|
129
|
+
end
|
130
|
+
|
131
|
+
# make sure to include requested methods
|
132
|
+
include_methods = method_include.split(",") if method_include.is_a?(String)
|
133
|
+
all_methods.each{|i| working_methods << i if include_methods.include?(i.attribute("name"))}
|
134
|
+
|
135
|
+
# make sure to exclude rejected methods
|
136
|
+
exclude_methods = method_exclude.split(",") if method_exclude.is_a?(String)
|
137
|
+
working_methods = working_methods.select{|i| not exclude_methods.include?(i.attribute("name"))}
|
138
|
+
|
139
|
+
# remove methods marked final
|
140
|
+
working_methods = working_methods.select{|i| (not i.attribute("final")) or i.attribute("final") == "false"}
|
141
|
+
|
142
|
+
# get additional methods from parent
|
143
|
+
if name =="class" and attribute("extends")
|
144
|
+
parent = root.find_class(attribute("extends"))
|
145
|
+
parent_methods = parent.all_methods(method_base, method_include, method_exclude)
|
146
|
+
working_signatures = working_methods.map(&:method_signature)
|
147
|
+
working_methods += parent_methods.select{|i| not working_signatures.include?(i.method_signature)}
|
148
|
+
end
|
149
|
+
|
150
|
+
# get additional methods from interfaces
|
151
|
+
if name =="class" and implements != ""
|
152
|
+
implements.split(",").each do |i|
|
153
|
+
interface = root.find_interface(i)
|
154
|
+
abort("Unkown interface: #{i}") unless interface
|
155
|
+
working_signatures = working_methods.map(&:method_signature)
|
156
|
+
working_methods += interface.all_methods.select{|j| not working_signatures.include?(j.method_signature)}
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
working_methods
|
161
|
+
end
|
162
|
+
|
163
|
+
def parameters
|
164
|
+
get_elements("parameter").map {|p| [p.attribute("name"), p.attribute("type").gsub("<", "<").gsub(">", ">")]}
|
165
|
+
end
|
166
|
+
|
167
|
+
def method_signature
|
168
|
+
"#{attribute("name")}(#{parameters.map{|i| i[1]}.join(',')})"
|
169
|
+
end
|
170
|
+
|
171
|
+
def constant_string
|
172
|
+
"CB_" + attribute("name").gsub(/[A-Z]/) {|i| "_#{i}"}.upcase.gsub(/^ON_/, "")
|
173
|
+
end
|
174
|
+
|
175
|
+
def super_string
|
176
|
+
if attribute("api_added") and
|
177
|
+
attribute("api_added").to_i > verify_min_sdk.to_i and
|
178
|
+
attribute("api_added").to_i <= verify_target_sdk.to_i
|
179
|
+
nil
|
180
|
+
elsif attribute("abstract") == "true"
|
181
|
+
nil
|
182
|
+
elsif name == "method"
|
183
|
+
"super.#{attribute("name")}(#{parameters.map{|i| i[0]}.join(", ")});"
|
184
|
+
elsif name == "constructor"
|
185
|
+
"super(#{parameters.map{|i| i[0]}.join(", ")});"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def default_return
|
190
|
+
return nil unless attribute("return")
|
191
|
+
case attribute("return")
|
192
|
+
when "boolean": "return false;"
|
193
|
+
when "int": "return 0;"
|
194
|
+
when "void": nil
|
195
|
+
else "return null;"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def super_return
|
200
|
+
rv = super_string
|
201
|
+
return rv unless attribute("return")
|
202
|
+
rv ? "return #{rv}" : default_return
|
203
|
+
end
|
204
|
+
|
205
|
+
def ruby_call
|
206
|
+
rv = []
|
207
|
+
|
208
|
+
params = parameters
|
209
|
+
args = ""
|
210
|
+
if params.size > 3
|
211
|
+
args = ", args"
|
212
|
+
rv << "IRubyObject[] args = {" + params.map{|i| "JavaUtil.convertJavaToRuby(getRuby(), #{i[0]})"}.join(", ") + "};"
|
213
|
+
elsif params.size > 0
|
214
|
+
args = ", " + params.map{|i| "JavaUtil.convertJavaToRuby(getRuby(), #{i[0]})"}.join(", ")
|
215
|
+
end
|
216
|
+
|
217
|
+
return_cast = ""
|
218
|
+
if attribute("return") and (attribute("return").include?(".") or attribute("return") == "int[]")
|
219
|
+
return_cast = "return (#{attribute("return")})"
|
220
|
+
elsif attribute("return") and attribute("return") == "int"
|
221
|
+
return_cast = "return (Integer)"
|
222
|
+
elsif attribute("return") and attribute("return") != "void"
|
223
|
+
return_cast = "return (#{attribute("return").capitalize})"
|
224
|
+
end
|
225
|
+
return_cast = return_cast.gsub("<", "<").gsub(">", ">")
|
226
|
+
|
227
|
+
convert_return = ""
|
228
|
+
if attribute("return") and attribute("return") != "void"
|
229
|
+
convert_return = ".toJava(#{attribute("return")}.class)"
|
230
|
+
end
|
231
|
+
|
232
|
+
rv << "#{return_cast}RuntimeHelpers.invoke(getRuby().getCurrentContext(), callbackProcs[#{constant_string}], \"call\" #{args})#{convert_return};"
|
233
|
+
rv
|
234
|
+
end
|
235
|
+
|
236
|
+
def method_definition
|
237
|
+
method_call((attribute("return") ? attribute("return") : "void"), attribute("name"), parameters,
|
238
|
+
if_else("callbackProcs[#{constant_string}] != null",
|
239
|
+
[super_string] + try_catch(ruby_call, ["re.printStackTrace();", default_return]),
|
240
|
+
[super_return])).indent.join("\n")
|
241
|
+
end
|
242
|
+
|
243
|
+
def constructor_definition(class_name)
|
244
|
+
method_call("", class_name, parameters, [super_string]).indent.join("\n")
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
###########################################################################
|
249
|
+
#
|
250
|
+
# Methods for formatting code
|
251
|
+
#
|
252
|
+
|
253
|
+
def method_call(return_type=nil, method_name="", parameters=[], body_clause=[])
|
254
|
+
["public #{return_type || ""} #{method_name}(" + parameters.map{|i| "#{i[1]} #{i[0]}"}.join(", ") + ") {",
|
255
|
+
body_clause.indent, "}"]
|
256
|
+
end
|
257
|
+
|
258
|
+
def if_else(condition, if_clause, else_clause)
|
259
|
+
["if (#{condition}) {", if_clause.indent, else_clause.compact.empty? ? nil : "} else {", else_clause.indent, "}"]
|
260
|
+
end
|
261
|
+
|
262
|
+
def try_catch(try_clause, catch_clause)
|
263
|
+
["try {", try_clause.indent, "} catch (RaiseException re) {", catch_clause.indent, "}"]
|
264
|
+
end
|
265
|
+
|
266
|
+
class Array
|
267
|
+
def indent
|
268
|
+
flatten.compact.map{|i| " " + i}
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
###########################################################################
|
273
|
+
#
|
274
|
+
# Build Subclass or Interface:
|
275
|
+
#
|
276
|
+
|
277
|
+
#
|
278
|
+
# build_file: Reads the src from the appropriate location,
|
279
|
+
# uses the substitutions hash to modify the contents,
|
280
|
+
# and writes to the new location
|
281
|
+
#
|
282
|
+
def build_file(src, package, name, substitutions, dest='.')
|
283
|
+
to = File.join(dest, "src/#{package.gsub('.', '/')}")
|
284
|
+
Dir.mkdir(to) unless File.directory?(to)
|
285
|
+
|
286
|
+
text = File.read(File.expand_path($gem_root + "/assets/src/#{src}.java"))
|
287
|
+
substitutions.each {|k,v| text.gsub!(k, v)}
|
288
|
+
|
289
|
+
File.open(File.join(to, "#{name}.java"), 'w') {|f| f << text}
|
290
|
+
end
|
291
|
+
|
292
|
+
#
|
293
|
+
# get_class_or_interface: Opens the xml file and locates the specified class.
|
294
|
+
# Aborts if the class is not found or if it is not available for
|
295
|
+
# all api levels
|
296
|
+
#
|
297
|
+
def get_class_or_interface(klass, force=false)
|
298
|
+
element = verify_api.find_class_or_interface(klass, "either")
|
299
|
+
|
300
|
+
abort "ERROR: #{klass} not found" unless element
|
301
|
+
|
302
|
+
unless force
|
303
|
+
abort "#{klass} not available in minSdkVersion, added in #{element.attribute('api_added')}; use --force to create it" if
|
304
|
+
element.attribute('api_added') and element.attribute('api_added').to_i > verify_min_sdk.to_i
|
305
|
+
abort "#{klass} deprecated for targetSdkVersion, deprecatrd in #{element.attribute('deprecated')}; use --force to create it" if
|
306
|
+
element.attribute('deprecated') and element.attribute('deprecated').to_i <= verify_target_sdk.to_i
|
307
|
+
end
|
308
|
+
|
309
|
+
abort "#{klass} removed for targetSdkVersion, removed in #{element.attribute('api_removed')}" if
|
310
|
+
element.attribute('api_removed') and element.attribute('api_removed').to_i <= verify_target_sdk.to_i
|
311
|
+
|
312
|
+
element
|
313
|
+
end
|
314
|
+
|
315
|
+
#
|
316
|
+
# check_methods: Checks the methods to see if they are available for all api levels
|
317
|
+
#
|
318
|
+
def check_methods(methods, force=false)
|
319
|
+
min_api = verify_min_sdk.to_i
|
320
|
+
target_api = verify_target_sdk.to_i
|
321
|
+
|
322
|
+
# Remove methods changed outside of the scope of the sdk versions
|
323
|
+
methods = methods.select{|i| not i.attribute('api_added') or i.attribute('api_added').to_i <= target_api}
|
324
|
+
methods = methods.select{|i| not i.attribute('deprecated') or i.attribute('deprecated').to_i > min_api}
|
325
|
+
methods = methods.select{|i| not i.attribute('api_removed') or i.attribute('api_removed').to_i > min_api}
|
326
|
+
|
327
|
+
# Inform and remove methods that do not exist in one of the sdk versions
|
328
|
+
methods = methods.select do |i|
|
329
|
+
if i.attribute('api_removed') and i.attribute('api_removed').to_i <= target_api
|
330
|
+
puts "Can't create #{i.method_signature} -- removed in #{i.attribute('api_removed')}"
|
331
|
+
false
|
332
|
+
else
|
333
|
+
true
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
new_methods = methods
|
338
|
+
unless force
|
339
|
+
# Inform and remove methods changed inside the scope of the sdk versions
|
340
|
+
new_methods = methods.select do |i|
|
341
|
+
if i.attribute('api_added') and i.attribute('api_added').to_i > min_api
|
342
|
+
puts "Can't create #{i.method_signature} -- added in #{i.attribute('api_added')} -- exclude or force"
|
343
|
+
false
|
344
|
+
elsif i.attribute('deprecated') and i.attribute('deprecated').to_i <= target_api
|
345
|
+
puts "Can't create #{i.method_signature} -- deprecated in #{i.attribute('deprecated')} -- exclude or force"
|
346
|
+
false
|
347
|
+
else
|
348
|
+
true
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
abort("Aborting!") if methods.count != new_methods.count
|
353
|
+
end
|
354
|
+
|
355
|
+
new_methods
|
356
|
+
end
|
357
|
+
|
358
|
+
#
|
359
|
+
# generate_subclass_or_interface: Creates a subclass or interface based on the specifications.
|
360
|
+
#
|
361
|
+
def generate_subclass_or_interface(params)
|
362
|
+
defaults = {:template => "InheritingClass", :method_base => "all", :method_include => "", :method_exclude => "", :force => false, :implements => ""}
|
363
|
+
params = defaults.merge(params)
|
364
|
+
params[:package] = verify_package unless params[:package]
|
365
|
+
|
366
|
+
class_desc = get_class_or_interface(params[:class] || params[:interface], params[:force])
|
367
|
+
|
368
|
+
puts "Generating methods for #{params[:name]}..."
|
369
|
+
methods = class_desc.all_methods(params[:method_base], params[:method_include], params[:method_exclude], params[:implements])
|
370
|
+
methods = check_methods(methods, params[:force])
|
371
|
+
puts "Done. Methods created: #{methods.count}"
|
372
|
+
|
373
|
+
# Remove any duplicate constants (use *args handle multiple parameter lists)
|
374
|
+
constants = methods.map(&:constant_string).uniq
|
375
|
+
|
376
|
+
build_file params[:template], params[:package], params[:name], {
|
377
|
+
"THE_PACKAGE" => params[:package],
|
378
|
+
"THE_ACTION" => class_desc.name == "class" ? "extends" : "implements",
|
379
|
+
"THE_ANDROID_CLASS" => (params[:class] || params[:interface]) +
|
380
|
+
(params[:implements] == "" ? "" : (" implements " + params[:implements].split(",").join(", "))),
|
381
|
+
"THE_RUBOTO_CLASS" => params[:name],
|
382
|
+
"THE_CONSTANTS" => constants.map {|i| "public static final int #{i} = #{constants.index(i)};"}.indent.join("\n"),
|
383
|
+
"CONSTANTS_COUNT" => methods.count.to_s,
|
384
|
+
"THE_CONSTRUCTORS" => class_desc.name == "class" ?
|
385
|
+
class_desc.get_elements("constructor").map{|i| i.constructor_definition(params[:name])}.join("\n\n") : "",
|
386
|
+
"THE_METHODS" => methods.map{|i| i.method_definition}.join("\n\n")
|
387
|
+
}
|
388
|
+
end
|
389
|
+
|
390
|
+
#
|
391
|
+
# generate_core_classe: generates RubotoActivity, RubotoService, etc. based
|
392
|
+
# on the API specifications.
|
393
|
+
#
|
394
|
+
def generate_core_classes(params)
|
395
|
+
%w(android.view.View.OnClickListener android.widget.AdapterView.OnItemClickListener).each do |i|
|
396
|
+
name = i.split(".")[-1]
|
397
|
+
if(params[:class] == name or params[:class] == "all")
|
398
|
+
generate_subclass_or_interface({:package => "org.ruboto.callbacks", :class => i, :name => "Ruboto#{name}"})
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
hash = {:package => "org.ruboto"}
|
403
|
+
%w(method_base method_include implements force).inject(hash) {|h, i| h[i.to_sym] = params[i.to_sym]; h}
|
404
|
+
hash[:method_exclude] = params[:method_exclude].split(",").push("onCreate").push("onReceive").join(",")
|
405
|
+
|
406
|
+
%w(android.app.Activity android.app.Service android.content.BroadcastReceiver android.view.View).each do |i|
|
407
|
+
name = i.split(".")[-1]
|
408
|
+
if(params[:class] == name or params[:class] == "all")
|
409
|
+
generate_subclass_or_interface(
|
410
|
+
hash.merge({:template => name == "View" ? "InheritingClass" : "Ruboto#{name}", :class => i, :name => "Ruboto#{name}"}))
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
# Activities that can be created, but only directly (i.e., not included in all)
|
415
|
+
%w(android.preference.PreferenceActivity android.app.TabActivity).each do |i|
|
416
|
+
name = i.split(".")[-1]
|
417
|
+
if params[:class] == name
|
418
|
+
generate_subclass_or_interface(hash.merge({:template => "RubotoActivity", :class => i, :name => "Ruboto#{name}"}))
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
###########################################################################
|
424
|
+
#
|
425
|
+
# Updating components
|
426
|
+
#
|
427
|
+
|
428
|
+
def update_jruby(force=nil)
|
429
|
+
jruby_core = Dir.glob("libs/jruby-core-*.jar")[0]
|
430
|
+
jruby_stdlib = Dir.glob("libs/jruby-stdlib-*.jar")[0]
|
431
|
+
new_jruby_version = JRubyJars::core_jar_path.split('/')[-1][11..-5]
|
432
|
+
|
433
|
+
unless force
|
434
|
+
abort "cannot find existing jruby jars in libs. Make sure you're in the root directory of your app" if
|
435
|
+
(not jruby_core or not jruby_stdlib)
|
436
|
+
|
437
|
+
current_jruby_version = jruby_core ? jruby_core[16..-5] : "None"
|
438
|
+
abort "both jruby versions are #{new_jruby_version}. Nothing to update. Make sure you 'gem update jruby-jars' if there is a new version" if
|
439
|
+
current_jruby_version == new_jruby_version
|
440
|
+
|
441
|
+
puts "Current jruby version: #{current_jruby_version}"
|
442
|
+
puts "New jruby version: #{new_jruby_version}"
|
443
|
+
end
|
444
|
+
|
445
|
+
copier = AssetCopier.new $assets, File.expand_path(".")
|
446
|
+
log_action("Removing #{jruby_core}") {File.delete jruby_core} if jruby_core
|
447
|
+
log_action("Removing #{jruby_stdlib}") {File.delete jruby_stdlib} if jruby_stdlib
|
448
|
+
log_action("Copying #{JRubyJars::core_jar_path} to libs") {copier.copy_from_absolute_path JRubyJars::core_jar_path, "libs"}
|
449
|
+
log_action("Copying #{JRubyJars::stdlib_jar_path} to libs") {copier.copy_from_absolute_path JRubyJars::stdlib_jar_path, "libs"}
|
450
|
+
|
451
|
+
reconfigure_jruby_libs
|
452
|
+
|
453
|
+
puts "JRuby version is now: #{new_jruby_version}"
|
454
|
+
end
|
455
|
+
|
456
|
+
def update_ruboto(force=nil)
|
457
|
+
verify_manifest
|
458
|
+
|
459
|
+
from = File.expand_path($gem_root + "/assets/assets/scripts/ruboto.rb")
|
460
|
+
to = File.expand_path("./assets/scripts/ruboto.rb")
|
461
|
+
|
462
|
+
from_text = File.read(from)
|
463
|
+
to_text = File.read(to) if File.exists?(to)
|
464
|
+
|
465
|
+
unless force
|
466
|
+
puts "New version: #{from_text[/\$RUBOTO_VERSION = (\d+)/, 1]}"
|
467
|
+
puts "Old version: #{to_text ? to_text[/\$RUBOTO_VERSION = (\d+)/, 1] : 'none'}"
|
468
|
+
|
469
|
+
abort "The ruboto.rb verion has not changed. Use --force to force update." if
|
470
|
+
from_text[/\$RUBOTO_VERSION = (\d+)/, 1] == to_text[/\$RUBOTO_VERSION = (\d+)/, 1]
|
471
|
+
end
|
472
|
+
|
473
|
+
log_action("Copying ruboto.rb and setting the package name") do
|
474
|
+
File.open(to, 'w') {|f| f << from_text.gsub("THE_PACKAGE", verify_package).gsub("ACTIVITY_NAME", verify_activity)}
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
#
|
479
|
+
# reconfigure_jruby_libs:
|
480
|
+
# - removes unneeded code from jruby-core
|
481
|
+
# - moves ruby stdlib to the root of the ruby-stdlib jar
|
482
|
+
#
|
483
|
+
|
484
|
+
def reconfigure_jruby_libs
|
485
|
+
jruby_core = JRubyJars::core_jar_path.split('/')[-1]
|
486
|
+
log_action("Removing unneeded classes from #{jruby_core}") do
|
487
|
+
Dir.mkdir "libs/tmp"
|
488
|
+
Dir.chdir "libs/tmp"
|
489
|
+
FileUtils.move "../#{jruby_core}", "."
|
490
|
+
`jar -xf #{jruby_core}`
|
491
|
+
File.delete jruby_core
|
492
|
+
['jni', 'org/jruby/ant', 'org/jruby/compiler/ir', 'org/jruby/demo', 'org/jruby/embed/bsf',
|
493
|
+
'org/jruby/embed/jsr223', 'org/jruby/ext/ffi','org/jruby/javasupport/bsf'
|
494
|
+
].each {|i| FileUtils.remove_dir i, true}
|
495
|
+
`jar -cf ../#{jruby_core} .`
|
496
|
+
Dir.chdir "../.."
|
497
|
+
FileUtils.remove_dir "libs/tmp", true
|
498
|
+
end
|
499
|
+
|
500
|
+
jruby_stdlib = JRubyJars::stdlib_jar_path.split('/')[-1]
|
501
|
+
log_action("Reformatting #{jruby_stdlib}") do
|
502
|
+
Dir.mkdir "libs/tmp"
|
503
|
+
Dir.chdir "libs/tmp"
|
504
|
+
FileUtils.move "../#{jruby_stdlib}", "."
|
505
|
+
`jar -xf #{jruby_stdlib}`
|
506
|
+
File.delete jruby_stdlib
|
507
|
+
FileUtils.move "META-INF/jruby.home/lib/ruby/1.8", ".."
|
508
|
+
Dir.chdir "../1.8"
|
509
|
+
FileUtils.remove_dir "../tmp", true
|
510
|
+
`jar -cf ../#{jruby_stdlib} .`
|
511
|
+
Dir.chdir "../.."
|
512
|
+
FileUtils.remove_dir "libs/1.8", true
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
###########################################################################
|
517
|
+
#
|
518
|
+
# Verify the presence of important components
|
519
|
+
#
|
520
|
+
|
521
|
+
def verify_manifest
|
522
|
+
abort "cannot find your AndroidManifest.xml to extract info from it. Make sure you're in the root directory of your app" unless
|
523
|
+
File.exists? 'AndroidManifest.xml'
|
524
|
+
@manifest ||= REXML::Document.new(File.read('AndroidManifest.xml')).root
|
525
|
+
end
|
526
|
+
|
527
|
+
def verify_package
|
528
|
+
verify_manifest
|
529
|
+
@package ||= @manifest.attribute('package').value
|
530
|
+
end
|
531
|
+
|
532
|
+
def verify_activity
|
533
|
+
verify_manifest
|
534
|
+
@activity ||= @manifest.elements['application/activity'].attribute('android:name').value
|
535
|
+
end
|
536
|
+
|
537
|
+
def verify_sdk_versions
|
538
|
+
verify_manifest
|
539
|
+
@uses_sdk ||= @manifest.elements["uses-sdk"]
|
540
|
+
abort "you must specify your sdk level in the manifest (e.g., <uses-sdk android:minSdkVersion='3' android:targetSdkVersion='8' />)" unless @uses_sdk
|
541
|
+
@uses_sdk
|
542
|
+
end
|
543
|
+
|
544
|
+
def verify_min_sdk
|
545
|
+
verify_sdk_versions
|
546
|
+
@min_sdk ||= @uses_sdk.attribute('android:minSdkVersion').value
|
547
|
+
abort "you must specify a minimum sdk level in the manifest (e.g., <uses-sdk android:minSdkVersion='3' android:targetSdkVersion='8' />)" unless @min_sdk
|
548
|
+
@min_sdk
|
549
|
+
end
|
550
|
+
|
551
|
+
def verify_target_sdk
|
552
|
+
verify_sdk_versions
|
553
|
+
@target_sdk ||= @uses_sdk.attribute('android:targetSdkVersion').value
|
554
|
+
abort "you must specify a target sdk level in the manifest (e.g., <uses-sdk android:minSdkVersion='3' android:targetSdkVersion='8' />)" unless @target_sdk
|
555
|
+
@target_sdk
|
556
|
+
end
|
557
|
+
|
558
|
+
def verify_api
|
559
|
+
unless $api
|
560
|
+
api = File.expand_path($gem_root + "/lib/java_class_gen/android_api.xml")
|
561
|
+
abort "cannot find android_api.xml to extract info from it." unless File.exists? api
|
562
|
+
log_action("Loading Android API") {$api = scan_in_api(File.read(api))["api"][0]}
|
563
|
+
end
|
564
|
+
$api
|
565
|
+
end
|
566
|
+
|
567
|
+
###########################################################################
|
568
|
+
#
|
569
|
+
# Scan the XML file. Much faster than using REXML.
|
570
|
+
#
|
571
|
+
|
572
|
+
def scan_in_api(file)
|
573
|
+
require 'strscan'
|
574
|
+
doc = StringScanner.new(file)
|
575
|
+
$api = XMLElement.new
|
576
|
+
parents = [$api]
|
577
|
+
|
578
|
+
while not doc.eos?
|
579
|
+
doc.scan(/</)
|
580
|
+
if doc.scan(/\/\w+>/)
|
581
|
+
parents.pop
|
582
|
+
else
|
583
|
+
name = doc.scan(/\w+/)
|
584
|
+
doc.scan(/\s+/)
|
585
|
+
values = {}
|
586
|
+
while not (term = doc.scan(/[\/>]/))
|
587
|
+
key = doc.scan(/\w+/)
|
588
|
+
doc.scan(/='/)
|
589
|
+
value = doc.scan(/[^']*/)
|
590
|
+
doc.scan(/'\s*/)
|
591
|
+
values[key] = value
|
592
|
+
end
|
593
|
+
element = parents[-1].add_element(name, values)
|
594
|
+
parents.push(element) if term == ">"
|
595
|
+
doc.scan(/>/) if term == "/"
|
596
|
+
end
|
597
|
+
end
|
598
|
+
$api
|
599
|
+
end
|
600
|
+
|
601
|
+
###########################################################################
|
602
|
+
#
|
603
|
+
# generate_inheriting_file:
|
604
|
+
# Builds a script based subclass of Activity, Service, or BroadcastReceiver
|
605
|
+
#
|
606
|
+
|
48
607
|
def generate_inheriting_file(klass, name, package, script_name, dest='.')
|
49
608
|
to = File.join(dest, "src/#{package.gsub('.', '/')}")
|
50
609
|
|
@@ -85,7 +644,14 @@ Main {
|
|
85
644
|
option("target") {
|
86
645
|
required
|
87
646
|
argument :required
|
88
|
-
|
647
|
+
defaults 'android-9'
|
648
|
+
description "android version to target. must begin with 'android-' (e.g., 'android-8' for froyo)"
|
649
|
+
}
|
650
|
+
option("min_sdk") {
|
651
|
+
required
|
652
|
+
argument :required
|
653
|
+
defaults 'android-7'
|
654
|
+
description "minimum android version supported. must begin with 'android-'. (default 'android-3')"
|
89
655
|
}
|
90
656
|
option("path"){
|
91
657
|
required
|
@@ -95,11 +661,13 @@ Main {
|
|
95
661
|
option("package"){
|
96
662
|
required
|
97
663
|
argument :required
|
664
|
+
defaults 'org.ruboto.example'
|
98
665
|
description "Name of package. Must be unique for every app. A common pattern is yourtld.yourdomain.appname (Ex. org.ruboto.irb)"
|
99
666
|
}
|
100
667
|
option("activity"){
|
101
668
|
required
|
102
669
|
argument :required
|
670
|
+
defaults 'Main'
|
103
671
|
description "name of your primary Activity"
|
104
672
|
}
|
105
673
|
|
@@ -107,15 +675,13 @@ Main {
|
|
107
675
|
path = params['path'].value
|
108
676
|
name = params['name'].value
|
109
677
|
target = params['target'].value
|
678
|
+
min_sdk = params['min_sdk'].value
|
110
679
|
package = params['package'].value
|
111
680
|
activity = params['activity'].value
|
112
681
|
|
113
682
|
abort "path must be to a directory that does not yet exist. it will be created" if
|
114
683
|
File.exists?(path)
|
115
684
|
|
116
|
-
abort "Currently you must set target to 'android-8' (Froyo) for ruboto to work" unless
|
117
|
-
target == 'android-8'
|
118
|
-
|
119
685
|
root = File.expand_path(path)
|
120
686
|
print "\nGenerating Android app #{name} in #{root}..."
|
121
687
|
`android create project -n #{name} -t #{target} -p #{path} -k #{package} -a #{activity}`
|
@@ -125,48 +691,35 @@ Main {
|
|
125
691
|
copier = AssetCopier.new $assets, root
|
126
692
|
|
127
693
|
%w{Rakefile .gitignore assets}.each do |f|
|
128
|
-
|
129
|
-
copier.copy f
|
130
|
-
puts "Done"
|
694
|
+
log_action(f) {copier.copy f}
|
131
695
|
end
|
132
696
|
|
133
|
-
|
134
|
-
copier.copy_from_absolute_path JRubyJars::core_jar_path, "libs"
|
135
|
-
copier.copy_from_absolute_path JRubyJars::stdlib_jar_path, "libs"
|
136
|
-
puts "Done"
|
697
|
+
log_action("Ruboto java classes"){copier.copy "src/org/ruboto/*.java", "src/org/ruboto"}
|
137
698
|
|
138
|
-
|
139
|
-
|
140
|
-
|
699
|
+
# Remember the current directory and chdir to the new app directory
|
700
|
+
current_dir = Dir.pwd
|
701
|
+
Dir.chdir root
|
141
702
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
<activity android:name="org.ruboto.RubotoDialog" android:theme="@android:style/Theme.Dialog">
|
151
|
-
</activity>
|
152
|
-
</application>
|
153
|
-
})
|
703
|
+
update_jruby true
|
704
|
+
|
705
|
+
log_action("\nAdding activities (RubotoActivity and RubotoDialog) and SDK versions to the manifest") do
|
706
|
+
verify_manifest.elements['application'].add_element 'activity', {"android:name" => "org.ruboto.RubotoActivity"}
|
707
|
+
verify_manifest.elements['application'].add_element 'activity', {"android:name" => "org.ruboto.RubotoDialog",
|
708
|
+
"android:theme" => "@android:style/Theme.Dialog"}
|
709
|
+
verify_manifest.add_element 'uses-sdk', {"android:minSdkVersion" => min_sdk[/\d+/], "android:targetSdkVersion" => target[/\d+/]}
|
710
|
+
File.open("AndroidManifest.xml", 'w') {|f| verify_manifest.document.write(f, 4)}
|
154
711
|
end
|
155
|
-
puts "Done"
|
156
712
|
|
157
|
-
|
158
|
-
java_files = [File.join(root, "assets/scripts/ruboto.rb")]
|
159
|
-
java_files.each do |file|
|
160
|
-
text = File.read(file)
|
161
|
-
File.open(file, 'w') do |f|
|
162
|
-
f << text.gsub("THE_PACKAGE", package).gsub("ACTIVITY_NAME", activity)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
puts "Done"
|
713
|
+
update_ruboto true
|
166
714
|
|
167
|
-
|
168
|
-
|
169
|
-
|
715
|
+
generate_core_classes(:class => "all", :method_base => "on", :method_include => "", :method_exclude => "", :force => true, :implements => "")
|
716
|
+
|
717
|
+
# Go back to whence we came
|
718
|
+
Dir.chdir current_dir
|
719
|
+
|
720
|
+
log_action("Generating the default Activity and script") do
|
721
|
+
generate_inheriting_file "Activity", activity, package, "#{underscore(activity)}.rb", path
|
722
|
+
end
|
170
723
|
|
171
724
|
puts "\nHello, #{name}\n"
|
172
725
|
end
|
@@ -191,15 +744,130 @@ Main {
|
|
191
744
|
|
192
745
|
|
193
746
|
def run
|
194
|
-
abort "cannot find your AndroidManifest.xml to extract info from it. Make sure you're in the root directory of your app" unless
|
195
|
-
File.exists? 'AndroidManifest.xml'
|
196
|
-
|
197
|
-
package = REXML::Document.new(File.read('AndroidManifest.xml')).root.attribute('package').value
|
198
747
|
name = params['name'].value
|
199
748
|
script_name = params['script_name'].value || "#{underscore(name)}.rb"
|
200
749
|
klass = params['class'].value
|
201
750
|
|
202
|
-
generate_inheriting_file klass, name,
|
751
|
+
generate_inheriting_file klass, name, verify_package, script_name
|
752
|
+
end
|
753
|
+
end
|
754
|
+
|
755
|
+
mode "subclass" do
|
756
|
+
argument("class"){
|
757
|
+
required
|
758
|
+
description "the Android Class that you want to subclass (e.g., package.Class)."
|
759
|
+
}
|
760
|
+
|
761
|
+
option("name"){
|
762
|
+
required
|
763
|
+
argument :required
|
764
|
+
description "name of the class (and file). Should be CamelCase"
|
765
|
+
}
|
766
|
+
|
767
|
+
option("method_base"){
|
768
|
+
required
|
769
|
+
validate {|i| %w(all on none abstract).include?(i)}
|
770
|
+
argument :required
|
771
|
+
description "the base set of methods to generate (adjusted with method_include and method_exclude): all, none, abstract, on (e.g., onClick)"
|
772
|
+
}
|
773
|
+
|
774
|
+
option("method_include"){
|
775
|
+
argument :required
|
776
|
+
defaults ""
|
777
|
+
description "additional methods to add to the base list"
|
778
|
+
}
|
779
|
+
|
780
|
+
option("method_exclude"){
|
781
|
+
argument :required
|
782
|
+
defaults ""
|
783
|
+
description "methods to remove from the base list"
|
784
|
+
}
|
785
|
+
|
786
|
+
option("implements"){
|
787
|
+
required
|
788
|
+
argument :required
|
789
|
+
defaults ""
|
790
|
+
description "comma separated list interfaces to implement"
|
791
|
+
}
|
792
|
+
|
793
|
+
option("force"){
|
794
|
+
cast :boolean
|
795
|
+
description "force added and deprecated methods not excluded to be create"
|
796
|
+
}
|
797
|
+
|
798
|
+
def run
|
799
|
+
generate_subclass_or_interface(
|
800
|
+
%w(class name method_base method_include method_exclude implements force).inject({}) {|h, i| h[i.to_sym] = params[i].value; h})
|
801
|
+
end
|
802
|
+
end
|
803
|
+
|
804
|
+
mode "interface" do
|
805
|
+
argument("interface"){
|
806
|
+
required
|
807
|
+
description "the Android Interface that you want to implement (e.g., package.Interface)."
|
808
|
+
}
|
809
|
+
|
810
|
+
option("name"){
|
811
|
+
required
|
812
|
+
argument :required
|
813
|
+
description "name of the class (and file) that will implement the interface. Should be CamelCase"
|
814
|
+
}
|
815
|
+
|
816
|
+
option("force"){
|
817
|
+
cast :boolean
|
818
|
+
description "force added and deprecated interfaces to be create"
|
819
|
+
}
|
820
|
+
|
821
|
+
def run
|
822
|
+
generate_subclass_or_interface %w(interface name force).inject({}) {|h, i| h[i.to_sym] = params[i].value; h}
|
823
|
+
end
|
824
|
+
end
|
825
|
+
|
826
|
+
mode "core" do
|
827
|
+
argument("class"){
|
828
|
+
required
|
829
|
+
validate {|i| %w(Activity Service BroadcastReceiver View PreferenceActivity TabActivity OnClickListener OnItemClickListener all).include?(i)}
|
830
|
+
description "Activity, Service, BroadcastReceiver, View, OnClickListener, OnItemClickListener, or all (default = all); Other activities not included in 'all': PreferenceActivity, TabActivity"
|
831
|
+
}
|
832
|
+
|
833
|
+
option("method_base"){
|
834
|
+
required
|
835
|
+
argument :required
|
836
|
+
validate {|i| %w(all on none).include?(i)}
|
837
|
+
defaults "on"
|
838
|
+
description "the base set of methods to generate (adjusted with method_include and method_exclude): all, none, on (e.g., onClick)"
|
839
|
+
}
|
840
|
+
|
841
|
+
option("method_include"){
|
842
|
+
required
|
843
|
+
argument :required
|
844
|
+
defaults ""
|
845
|
+
description "additional methods to add to the base list"
|
846
|
+
}
|
847
|
+
|
848
|
+
option("method_exclude"){
|
849
|
+
required
|
850
|
+
argument :required
|
851
|
+
defaults ""
|
852
|
+
description "methods to remove from the base list"
|
853
|
+
}
|
854
|
+
|
855
|
+
option("implements"){
|
856
|
+
required
|
857
|
+
argument :required
|
858
|
+
defaults ""
|
859
|
+
description "for classes only, interfaces to implement (cannot be used with 'gen core all')"
|
860
|
+
}
|
861
|
+
|
862
|
+
option("force"){
|
863
|
+
cast :boolean
|
864
|
+
description "force added and deprecated methods not excluded to be create"
|
865
|
+
}
|
866
|
+
|
867
|
+
def run
|
868
|
+
abort("specify 'implements' only for Activity, Service, BroadcastReceiver, PreferenceActivity, or TabActivity") unless
|
869
|
+
%w(Activity Service BroadcastReceiver PreferenceActivity TabActivity).include?(params["class"].value) or params["implements"].value == ""
|
870
|
+
generate_core_classes [:class, :method_base, :method_include, :method_exclude, :implements, :force].inject({}) {|h, i| h[i] = params[i.to_s].value; h}
|
203
871
|
end
|
204
872
|
end
|
205
873
|
|
@@ -223,11 +891,31 @@ Main {
|
|
223
891
|
end
|
224
892
|
end
|
225
893
|
|
894
|
+
mode "update-jruby" do
|
895
|
+
argument("what"){
|
896
|
+
required
|
897
|
+
validate {|i| %w(jruby ruboto).include?(i)}
|
898
|
+
description "What do you want to update: 'jruby' or 'ruboto'"
|
899
|
+
}
|
900
|
+
|
901
|
+
option("force"){
|
902
|
+
description "force and update even if the version hasn't changed"
|
903
|
+
}
|
904
|
+
|
905
|
+
def run
|
906
|
+
case params['what'].value
|
907
|
+
when "jruby": update_jruby(params['force'].value);
|
908
|
+
when "ruboto": update_ruboto(params['force'].value);
|
909
|
+
end
|
910
|
+
end
|
911
|
+
end
|
912
|
+
|
226
913
|
# just running `ruboto`
|
227
914
|
def run
|
228
915
|
puts %Q{
|
229
916
|
Ruboto -- Ruby for Android
|
230
917
|
Execute `ruboto gen app --help` for instructions on how to generate a fresh Ruby-enabled Android app
|
918
|
+
Execute `ruboto --help` for other options
|
231
919
|
}
|
232
920
|
end
|
233
921
|
}
|