ruboto 0.5.2

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 (67) hide show
  1. data/COPYING +19 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +21 -0
  4. data/README.md +293 -0
  5. data/Rakefile +114 -0
  6. data/assets/Rakefile +386 -0
  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/res/layout/get_ruboto_core.xml +25 -0
  11. data/assets/samples/sample_activity.rb +21 -0
  12. data/assets/samples/sample_activity_test.rb +21 -0
  13. data/assets/samples/sample_broadcast_receiver.rb +6 -0
  14. data/assets/samples/sample_broadcast_receiver_test.rb +1 -0
  15. data/assets/samples/sample_service.rb +14 -0
  16. data/assets/samples/sample_service_test.rb +1 -0
  17. data/assets/src/InheritingActivity.java +195 -0
  18. data/assets/src/InheritingBroadcastReceiver.java +27 -0
  19. data/assets/src/InheritingClass.java +19 -0
  20. data/assets/src/InheritingService.java +9 -0
  21. data/assets/src/RubotoActivity.java +111 -0
  22. data/assets/src/RubotoBroadcastReceiver.java +51 -0
  23. data/assets/src/RubotoService.java +61 -0
  24. data/assets/src/org/ruboto/RubotoDialog.java +11 -0
  25. data/assets/src/org/ruboto/Script.java +545 -0
  26. data/assets/src/org/ruboto/test/ActivityTest.java +63 -0
  27. data/assets/src/org/ruboto/test/InstrumentationTestRunner.java +124 -0
  28. data/assets/src/ruboto.rb +621 -0
  29. data/assets/test/assets/scripts/test_helper.rb +13 -0
  30. data/bin/ruboto +5 -0
  31. data/lib/java_class_gen/InheritingClass.java.erb +10 -0
  32. data/lib/java_class_gen/android_api.xml +1 -0
  33. data/lib/ruboto.rb +16 -0
  34. data/lib/ruboto/api.rb +21 -0
  35. data/lib/ruboto/commands/base.rb +392 -0
  36. data/lib/ruboto/core_ext/array.rb +6 -0
  37. data/lib/ruboto/core_ext/object.rb +10 -0
  38. data/lib/ruboto/util/asset_copier.rb +27 -0
  39. data/lib/ruboto/util/build.rb +201 -0
  40. data/lib/ruboto/util/code_formatting.rb +22 -0
  41. data/lib/ruboto/util/log_action.rb +20 -0
  42. data/lib/ruboto/util/main_fix.rb +13 -0
  43. data/lib/ruboto/util/objectspace.rb +8 -0
  44. data/lib/ruboto/util/scan_in_api.rb +40 -0
  45. data/lib/ruboto/util/update.rb +420 -0
  46. data/lib/ruboto/util/verify.rb +87 -0
  47. data/lib/ruboto/util/xml_element.rb +200 -0
  48. data/lib/ruboto/version.rb +3 -0
  49. data/test/activity/image_button_activity.rb +21 -0
  50. data/test/activity/image_button_activity_test.rb +21 -0
  51. data/test/activity/image_button_and_button_activity.rb +24 -0
  52. data/test/activity/image_button_and_button_activity_test.rb +27 -0
  53. data/test/activity/option_menu_activity.rb +21 -0
  54. data/test/activity/option_menu_activity_test.rb +20 -0
  55. data/test/activity/stack_activity.rb +21 -0
  56. data/test/activity/stack_activity_test.rb +23 -0
  57. data/test/app_test_methods.rb +41 -0
  58. data/test/minimal_app_test.rb +23 -0
  59. data/test/rake_test.rb +40 -0
  60. data/test/ruboto_gen_test.rb +32 -0
  61. data/test/ruboto_gen_with_psych_test.rb +16 -0
  62. data/test/ruboto_update_test.rb +5 -0
  63. data/test/ruboto_update_with_psych_test.rb +18 -0
  64. data/test/service_test.rb +49 -0
  65. data/test/test_helper.rb +177 -0
  66. data/test/update_test_methods.rb +33 -0
  67. metadata +157 -0
@@ -0,0 +1,87 @@
1
+ require 'ruboto/api'
2
+ require 'yaml'
3
+
4
+ module Ruboto
5
+ module Util
6
+ module Verify
7
+ ###########################################################################
8
+ #
9
+ # Verify the presence of important components
10
+ #
11
+
12
+ def verify_manifest
13
+ abort "cannot find your AndroidManifest.xml to extract info from it. Make sure you're in the root directory of your app" unless
14
+ File.exists? 'AndroidManifest.xml'
15
+ @manifest ||= REXML::Document.new(File.read('AndroidManifest.xml')).root
16
+ end
17
+
18
+ def save_manifest
19
+ File.open("AndroidManifest.xml", 'w') {|f| verify_manifest.document.write(f, 4)}
20
+ end
21
+
22
+ def verify_test_manifest
23
+ abort "cannot find your test AndroidManifest.xml to extract info from it. Make sure you're in the root directory of your app" \
24
+ unless File.exists? 'test/AndroidManifest.xml'
25
+ @manifest ||= REXML::Document.new(File.read('test/AndroidManifest.xml')).root
26
+ end
27
+
28
+ def save_test_manifest
29
+ File.open("test/AndroidManifest.xml", 'w') {|f| verify_test_manifest.document.write(f, 4)}
30
+ end
31
+
32
+ def verify_package
33
+ verify_manifest
34
+ @package ||= @manifest.attribute('package').value
35
+ end
36
+
37
+ def verify_activity
38
+ verify_manifest
39
+ @activity ||= @manifest.elements['application/activity'].attribute('android:name').value
40
+ end
41
+
42
+ def verify_sdk_versions
43
+ verify_manifest
44
+ @uses_sdk ||= @manifest.elements["uses-sdk"]
45
+ abort "you must specify your sdk level in the manifest (e.g., <uses-sdk android:minSdkVersion='3' android:targetSdkVersion='8' />)" unless @uses_sdk
46
+ @uses_sdk
47
+ end
48
+
49
+ def verify_min_sdk
50
+ verify_sdk_versions
51
+ @min_sdk ||= @uses_sdk.attribute('android:minSdkVersion').value
52
+ abort "you must specify a minimum sdk level in the manifest (e.g., <uses-sdk android:minSdkVersion='3' android:targetSdkVersion='8' />)" unless @min_sdk
53
+ @min_sdk
54
+ end
55
+
56
+ def verify_target_sdk
57
+ verify_sdk_versions
58
+ @target_sdk ||= @uses_sdk.attribute('android:targetSdkVersion').value
59
+ abort "you must specify a target sdk level in the manifest (e.g., <uses-sdk android:minSdkVersion='3' android:targetSdkVersion='8' />)" unless @target_sdk
60
+ @target_sdk
61
+ end
62
+
63
+ def verify_strings
64
+ abort "cannot find your strings.xml to extract info from it. Make sure you're in the root directory of your app" unless
65
+ File.exists? 'res/values/strings.xml'
66
+ @strings ||= REXML::Document.new(File.read('res/values/strings.xml'))
67
+ end
68
+
69
+ def verify_api
70
+ Ruboto::API.api
71
+ end
72
+
73
+ def verify_ruboto_config
74
+ if File.exists? 'ruboto.yml'
75
+ @ruboto_config ||= YAML::load_file('ruboto.yml')
76
+ else
77
+ @ruboto_config = {}
78
+ end
79
+ end
80
+
81
+ def save_ruboto_config
82
+ File.open("ruboto.yml", 'w') {|f| YAML.dump verify_ruboto_config}
83
+ end
84
+
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,200 @@
1
+ require 'ruboto/util/code_formatting'
2
+ require 'ruboto/util/verify'
3
+ require 'ruboto/api'
4
+
5
+ module Ruboto
6
+ module Util
7
+ ###########################################################################
8
+ #
9
+ # XMLElement:
10
+ # Extends Hash to simulate a REXML::Element (but much faster) and provides
11
+ # information in the necessary format to generate Java code.
12
+ #
13
+ class XMLElement < Hash
14
+ include Ruboto::Util::CodeFormatting
15
+ include Ruboto::Util::Verify
16
+
17
+ def root
18
+ Ruboto::API.api
19
+ end
20
+
21
+ def name
22
+ self["name"]
23
+ end
24
+
25
+ def attribute(name)
26
+ self["values"][name]
27
+ end
28
+
29
+ def add_element(name, attributes)
30
+ new_element = XMLElement.new
31
+ new_element["name"] = name
32
+ new_element["values"] = attributes
33
+
34
+ self[name] = [] unless self[name]
35
+ self[name] << new_element
36
+
37
+ new_element
38
+ end
39
+
40
+ def get_elements(name)
41
+ self[name] or []
42
+ end
43
+
44
+ def find_class_or_interface(klass, a_type)
45
+ abort "ERROR: Can't parse package from #{klass}" unless klass.match(/([a-z.]+)\.([A-Z][A-Za-z.]+)/)
46
+
47
+ package = self["package"].find{|i| i.attribute("name") == $1}
48
+ abort "ERROR: Can't find package #{$1}" unless package
49
+ if a_type == "either"
50
+ package["class"].find{|i| i.attribute("name") == $2} or package["interface"].find{|i| i.attribute("name") == $2}
51
+ else
52
+ package[a_type].find{|i| i.attribute("name") == $2}
53
+ end
54
+ end
55
+
56
+ def find_class(package_and_class)
57
+ find_class_or_interface(package_and_class, "class")
58
+ end
59
+
60
+ def find_interface(package_and_interface)
61
+ find_class_or_interface(package_and_interface, "interface")
62
+ end
63
+
64
+ def all_methods(method_base="all", method_include="", method_exclude="", implements="")
65
+ # get all the methogs
66
+ all_methods = get_elements("method")
67
+
68
+ # establish the base set of methods
69
+ working_methods = case method_base
70
+ when "all" then
71
+ all_methods
72
+ when "none" then
73
+ []
74
+ when "abstract" then
75
+ all_methods.select{|i| i.attribute("abstract") == "true"}
76
+ when "on" then
77
+ all_methods.select{|i| i.attribute("name").match(/^on[A-Z]/)}
78
+ end
79
+
80
+ # make sure to include requested methods
81
+ include_methods = method_include.split(",") if method_include.is_a?(String)
82
+ all_methods.each{|i| working_methods << i if include_methods.include?(i.attribute("name"))}
83
+
84
+ # make sure to exclude rejected methods
85
+ exclude_methods = method_exclude.split(",") if method_exclude.is_a?(String)
86
+ working_methods = working_methods.select{|i| not exclude_methods.include?(i.attribute("name"))}
87
+
88
+ # remove methods marked final
89
+ working_methods = working_methods.select{|i| (not i.attribute("final")) or i.attribute("final") == "false"}
90
+
91
+ # get additional methods from parent
92
+ if name =="class" and attribute("extends")
93
+ parent = root.find_class(attribute("extends"))
94
+ parent_methods = parent.all_methods(method_base, method_include, method_exclude)
95
+ working_signatures = working_methods.map(&:method_signature)
96
+ working_methods += parent_methods.select{|i| not working_signatures.include?(i.method_signature)}
97
+ end
98
+
99
+ # get additional methods from interfaces
100
+ if name =="class" and implements != ""
101
+ implements.split(",").each do |i|
102
+ interface = root.find_interface(i)
103
+ abort("Unkown interface: #{i}") unless interface
104
+ working_signatures = working_methods.map(&:method_signature)
105
+ working_methods += interface.all_methods.select{|j| not working_signatures.include?(j.method_signature)}
106
+ end
107
+ end
108
+
109
+ working_methods
110
+ end
111
+
112
+ def parameters
113
+ get_elements("parameter").map {|p| [p.attribute("name"), p.attribute("type").gsub("&lt;", "<").gsub("&gt;", ">")]}
114
+ end
115
+
116
+ def method_signature
117
+ "#{attribute("name")}(#{parameters.map{|i| i[1]}.join(',')})"
118
+ end
119
+
120
+ def constant_string
121
+ "CB_" + attribute("name").gsub(/[A-Z]/) {|i| "_#{i}"}.upcase.gsub(/^ON_/, "")
122
+ end
123
+
124
+ def super_string
125
+ if attribute("api_added") and
126
+ attribute("api_added").to_i > verify_min_sdk.to_i and
127
+ attribute("api_added").to_i <= verify_target_sdk.to_i
128
+ nil
129
+ elsif attribute("abstract") == "true"
130
+ nil
131
+ elsif name == "method"
132
+ "super.#{attribute("name")}(#{parameters.map{|i| i[0]}.join(", ")});"
133
+ elsif name == "constructor"
134
+ "super(#{parameters.map{|i| i[0]}.join(", ")});"
135
+ end
136
+ end
137
+
138
+ def default_return
139
+ return nil unless attribute("return")
140
+ case attribute("return")
141
+ when "boolean" then "return false;"
142
+ when "int" then "return 0;"
143
+ when "void" then nil
144
+ else "return null;"
145
+ end
146
+ end
147
+
148
+ def super_return
149
+ rv = super_string
150
+ return rv unless attribute("return")
151
+ rv ? "return #{rv}" : default_return
152
+ end
153
+
154
+ def ruby_call
155
+ rv = []
156
+
157
+ params = parameters
158
+ args = ""
159
+ if params.size > 1
160
+ args = ", new Object[]{" + params.map{|i| i[0]}.join(", ") + "}"
161
+ elsif params.size > 0
162
+ args = ", " + params.map{|i| i[0]}.join(", ")
163
+ end
164
+
165
+ return_cast = ""
166
+ convert_return = ""
167
+ if attribute("return") && attribute("return") != "void"
168
+ if (attribute("return").include?(".") or attribute("return") == "int[]")
169
+ return_class = attribute("return")
170
+ elsif attribute("return") == 'int'
171
+ return_class = 'Integer'
172
+ else
173
+ return_class = attribute("return").capitalize
174
+ end
175
+ return_cast = "return (#{return_class.gsub("&lt;", "<").gsub("&gt;", ">")}) " if return_class
176
+ convert_return = ", #{return_class}.class"
177
+ end
178
+
179
+ rv << "#{return_cast}Script.callMethod(callbackProcs[#{constant_string}], \"call\" #{args}#{convert_return});"
180
+ rv
181
+ end
182
+
183
+ def method_definition
184
+ method_call(
185
+ (attribute("return") ? attribute("return") : "void"),
186
+ attribute("name"), parameters,
187
+ if_else(
188
+ "callbackProcs[#{constant_string}] != null",
189
+ [super_string] + ruby_call,
190
+ [super_return]
191
+ )
192
+ ).indent.join("\n")
193
+ end
194
+
195
+ def constructor_definition(class_name)
196
+ method_call("", class_name, parameters, [super_string]).indent.join("\n")
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,3 @@
1
+ module Ruboto
2
+ VERSION = '0.5.2'
3
+ end
@@ -0,0 +1,21 @@
1
+ require 'ruboto'
2
+
3
+ ruboto_import_widgets :ImageButton, :LinearLayout, :TextView
4
+
5
+ $activity.handle_create do |bundle|
6
+ setTitle File.basename(__FILE__).chomp('_activity.rb').split('_').map{|s| "#{s[0..0].upcase}#{s[1..-1]}" }.join(' ')
7
+
8
+ setup_content do
9
+ linear_layout :orientation => LinearLayout::VERTICAL do
10
+ @text_view = text_view :text => 'What hath Matz wrought?', :id => 42
11
+ image_button :image_resource => $package.R::drawable::icon, :width => :wrap_content, :id => 43
12
+ end
13
+ end
14
+
15
+ handle_click do |view|
16
+ if view.id == 43
17
+ @text_view.setText 'What hath Matz wrought!'
18
+ toast 'Flipped a bit via butterfly'
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ activity Java::org.ruboto.test_app.ImageButtonActivity
2
+
3
+ setup do |activity|
4
+ start = Time.now
5
+ loop do
6
+ @text_view = activity.findViewById(42)
7
+ break if @text_view || (Time.now - start > 60)
8
+ sleep 1
9
+ end
10
+ assert @text_view
11
+ end
12
+
13
+ test('initial setup') do |activity|
14
+ assert_equal "What hath Matz wrought?", @text_view.text
15
+ end
16
+
17
+ test('button changes text') do |activity|
18
+ button = activity.findViewById(43)
19
+ button.performClick
20
+ assert_equal "What hath Matz wrought!", @text_view.text
21
+ end
@@ -0,0 +1,24 @@
1
+ require 'ruboto'
2
+
3
+ ruboto_import_widgets :Button, :ImageButton, :LinearLayout, :TextView
4
+
5
+ $activity.handle_create do |bundle|
6
+ setTitle File.basename(__FILE__).chomp('_activity.rb').split('_').map{|s| "#{s[0..0].upcase}#{s[1..-1]}" }.join(' ')
7
+
8
+ setup_content do
9
+ linear_layout :orientation => LinearLayout::VERTICAL do
10
+ @text_view = text_view :text => 'What hath Matz wrought?', :id => 42
11
+ button :text => 'Button', :width => :wrap_content, :id => 44
12
+ image_button :image_resource => $package.R::drawable::icon, :width => :wrap_content, :id => 43
13
+ end
14
+ end
15
+
16
+ handle_click do |view|
17
+ if view.id == 43
18
+ @text_view.text = 'Image button pressed'
19
+ elsif view.id == 44
20
+ @text_view.text = 'Button pressed'
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,27 @@
1
+ activity Java::org.ruboto.test_app.ImageButtonAndButtonActivity
2
+
3
+ setup do |activity|
4
+ start = Time.now
5
+ loop do
6
+ @text_view = activity.find_view_by_id 42
7
+ break if @text_view || (Time.now - start > 60)
8
+ sleep 1
9
+ end
10
+ assert @text_view
11
+ end
12
+
13
+ test('initial setup') do |activity|
14
+ assert_equal "What hath Matz wrought?", @text_view.text
15
+ end
16
+
17
+ test('button changes text') do |activity|
18
+ button = activity.find_view_by_id 44
19
+ button.perform_click
20
+ assert_equal 'Button pressed', @text_view.text
21
+ end
22
+
23
+ test('image button changes text') do |activity|
24
+ image_button = activity.find_view_by_id 43
25
+ image_button.perform_click
26
+ assert_equal 'Image button pressed', @text_view.text
27
+ end
@@ -0,0 +1,21 @@
1
+ require 'ruboto'
2
+
3
+ ruboto_import_widgets :ImageButton, :LinearLayout, :TextView
4
+
5
+ $activity.handle_create do |bundle|
6
+ setTitle File.basename(__FILE__).chomp('_activity.rb').split('_').map{|s| "#{s[0..0].upcase}#{s[1..-1]}" }.join(' ')
7
+
8
+ setup_content do
9
+ linear_layout :orientation => LinearLayout::VERTICAL do
10
+ @text_view = text_view :text => 'What hath Matz wrought?', :id => 42
11
+ end
12
+ end
13
+
14
+ handle_create_options_menu do |menu|
15
+ add_menu('Test') do
16
+ @text_view.setText 'What hath Matz wrought!'
17
+ toast 'Flipped a bit via butterfly'
18
+ end
19
+ true
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ activity Java::org.ruboto.test_app.OptionMenuActivity
2
+
3
+ setup do |activity|
4
+ start = Time.now
5
+ loop do
6
+ @text_view = activity.findViewById(42)
7
+ break if @text_view || (Time.now - start > 60)
8
+ sleep 1
9
+ end
10
+ assert @text_view
11
+ end
12
+
13
+ test('initial setup') do |activity|
14
+ assert_equal "What hath Matz wrought?", @text_view.text
15
+ end
16
+
17
+ test('option_menu changes text') do |activity|
18
+ activity.window.performPanelIdentifierAction(android.view.Window::FEATURE_OPTIONS_PANEL, 0, 0)
19
+ assert_equal "What hath Matz wrought!", @text_view.text
20
+ end
@@ -0,0 +1,21 @@
1
+ STACK_DEPTH_SCRIPT = java.lang.Thread.current_thread.stack_trace.length.to_s
2
+ require 'ruboto'
3
+
4
+ ruboto_import_widgets :Button, :LinearLayout, :TextView
5
+
6
+ $activity.handle_create do |bundle|
7
+ STACK_DEPTH_HANDLE_CREATE = java.lang.Thread.current_thread.stack_trace.length.to_s
8
+ setTitle File.basename(__FILE__).chomp('_activity.rb').split('_').map{|s| "#{s[0..0].upcase}#{s[1..-1]}" }.join(' ')
9
+
10
+ setup_content do
11
+ STACK_DEPTH_SETUP_CONTENT = java.lang.Thread.current_thread.stack_trace.length.to_s
12
+ linear_layout :orientation => LinearLayout::VERTICAL do
13
+ STACK_DEPTH_LINEAR_LAYOUT = java.lang.Thread.current_thread.stack_trace.length.to_s
14
+ @script_view = text_view :id => 42, :text => STACK_DEPTH_SCRIPT
15
+ @handle_create_view = text_view :id => 43, :text => STACK_DEPTH_HANDLE_CREATE
16
+ @setup_content_view = text_view :id => 44, :text => STACK_DEPTH_SETUP_CONTENT
17
+ @linear_layout_view = text_view :id => 45, :text => STACK_DEPTH_LINEAR_LAYOUT
18
+ end
19
+ end
20
+
21
+ end