Module: Ruboto::Util::Build

Includes:
Verify
Defined in:
lib/ruboto/util/build.rb

Instance Method Summary collapse

Methods included from Verify

#verify_activity, #verify_api, #verify_manifest, #verify_min_sdk, #verify_package, #verify_sdk_versions, #verify_strings, #verify_target_sdk

Instance Method Details

#build_file(src, package, name, substitutions, dest = '.') ⇒ Object

build_file: Reads the src from the appropriate location,

uses the substitutions hash to modify the contents,
and writes to the new location


15
16
17
18
19
20
21
22
23
# File 'lib/ruboto/util/build.rb', line 15

def build_file(src, package, name, substitutions, dest='.')
  to = File.join(dest, "src/#{package.gsub('.', '/')}")
  Dir.mkdir(to) unless File.directory?(to)

  text = File.read(File.expand_path(Ruboto::GEM_ROOT + "/assets/src/#{src}.java"))
  substitutions.each {|k,v| text.gsub!(k, v)}

  File.open(File.join(to, "#{name}.java"), 'w') {|f| f << text}
end

#check_methods(methods, force = false) ⇒ Object

check_methods: Checks the methods to see if they are available for all api levels



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/ruboto/util/build.rb', line 51

def check_methods(methods, force=false)
  min_api = verify_min_sdk.to_i
  target_api = verify_target_sdk.to_i

  # Remove methods changed outside of the scope of the sdk versions
  methods = methods.select{|i| not i.attribute('api_added') or i.attribute('api_added').to_i <= target_api}
  methods = methods.select{|i| not i.attribute('deprecated') or i.attribute('deprecated').to_i > min_api}
  methods = methods.select{|i| not i.attribute('api_removed') or i.attribute('api_removed').to_i > min_api}

  # Inform and remove methods that do not exist in one of the sdk versions
  methods = methods.select do |i|
    if i.attribute('api_removed') and i.attribute('api_removed').to_i <= target_api
      puts "Can't create #{i.method_signature} -- removed in #{i.attribute('api_removed')}"
      false
    else
      true
    end
  end

  new_methods = methods
  unless force
    # Inform and remove methods changed inside the scope of the sdk versions
    new_methods = methods.select do |i|
      if i.attribute('api_added') and i.attribute('api_added').to_i > min_api
        puts "Can't create #{i.method_signature} -- added in #{i.attribute('api_added')} -- exclude or force"
        false
      elsif i.attribute('deprecated') and i.attribute('deprecated').to_i <= target_api
        puts "Can't create #{i.method_signature} -- deprecated in #{i.attribute('deprecated')} -- exclude or force"
        false
      else
        true
      end
    end

    abort("Aborting!") if methods.count != new_methods.count
  end

  new_methods
end

#generate_core_classes(params) ⇒ Object

generate_core_classe: generates RubotoActivity, RubotoService, etc. based

on the API specifications.


127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/ruboto/util/build.rb', line 127

def generate_core_classes(params)
  %w(android.view.View.OnClickListener android.widget.AdapterView.OnItemClickListener).each do |i|
    name = i.split(".")[-1]
    if(params[:class] == name or params[:class] == "all")
      generate_subclass_or_interface({:package => "org.ruboto.callbacks", :class => i, :name => "Ruboto#{name}"})
    end
  end

  hash = {:package => "org.ruboto"}
  %w(method_base method_include implements force).inject(hash) {|h, i| h[i.to_sym] = params[i.to_sym]; h}
  hash[:method_exclude] = params[:method_exclude].split(",").push("onCreate").push("onReceive").join(",")

  %w(android.app.Activity android.app.Service android.content.BroadcastReceiver android.view.View).each do |i|
    name = i.split(".")[-1]
    if(params[:class] == name or params[:class] == "all")
      generate_subclass_or_interface(
      hash.merge({:template => name == "View" ? "InheritingClass" : "Ruboto#{name}", :class => i, :name => "Ruboto#{name}"}))
    end
  end

  # Activities that can be created, but only directly  (i.e., not included in all)
  %w(android.preference.PreferenceActivity android.app.TabActivity).each do |i|
    name = i.split(".")[-1]
    if params[:class] == name
      generate_subclass_or_interface(hash.merge({:template => "RubotoActivity", :class => i, :name => "Ruboto#{name}"}))
    end
  end
end

#generate_inheriting_file(klass, name, package, script_name, dest = '.', filename = name) ⇒ Object

generate_inheriting_file:

Builds a script based subclass of Activity, Service, or BroadcastReceiver


162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/ruboto/util/build.rb', line 162

def generate_inheriting_file(klass, name, package, script_name, dest='.', filename = name)
  file = File.join(dest, "src/#{package.gsub('.', '/')}", "#{filename}.java")
  text = File.read(File.join(Ruboto::ASSETS, "src/Inheriting#{klass}.java"))
  File.open(file, 'w') do |f|
    f << text.gsub("THE_PACKAGE", package).gsub("Inheriting#{klass}", name).gsub("start.rb", script_name)
  end

  sample_source = File.read(File.join(Ruboto::ASSETS, "samples/sample_#{underscore klass}.rb")).gsub("THE_PACKAGE", package).gsub("Sample#{klass}", name).gsub("start.rb", script_name)
  FileUtils.mkdir_p File.join(dest, 'assets/scripts')
  File.open File.join(dest, "assets/scripts/#{script_name}"), "a" do |f|
    f << sample_source
  end

  sample_test_source = File.read(File.join(Ruboto::ASSETS, "samples/sample_#{underscore klass}_test.rb")).gsub("THE_PACKAGE", package).gsub("Sample#{klass}", name)
  FileUtils.mkdir_p File.join(dest, 'test/assets/scripts')
  File.open File.join(dest, "test/assets/scripts/#{script_name.chomp('.rb')}_test.rb"), "a" do |f|
    f << sample_test_source
  end
end

#generate_subclass_or_interface(params) ⇒ Object

generate_subclass_or_interface: Creates a subclass or interface based on the specifications.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/ruboto/util/build.rb', line 94

def generate_subclass_or_interface(params)
  defaults = {:template => "InheritingClass", :method_base => "all", :method_include => "", :method_exclude => "", :force => false, :implements => ""}
  params = defaults.merge(params)
  params[:package] = verify_package unless params[:package]

  class_desc = get_class_or_interface(params[:class] || params[:interface], params[:force])

  puts "Generating methods for #{params[:name]}..."
  methods = class_desc.all_methods(params[:method_base], params[:method_include], params[:method_exclude], params[:implements])
  methods = check_methods(methods, params[:force])
  puts "Done. Methods created: #{methods.count}"

  # Remove any duplicate constants (use *args handle multiple parameter lists)
  constants = methods.map(&:constant_string).uniq

  build_file params[:template], params[:package], params[:name], {
    "THE_PACKAGE" => params[:package],
    "THE_ACTION" => class_desc.name == "class" ? "extends" : "implements",
    "THE_ANDROID_CLASS" => (params[:class] || params[:interface]) +
    (params[:implements] == "" ? "" : (" implements " + params[:implements].split(",").join(", "))),
    "THE_RUBOTO_CLASS" => params[:name],
    "THE_CONSTANTS" =>  constants.map {|i| "public static final int #{i} = #{constants.index(i)};"}.indent.join("\n"),
    "CONSTANTS_COUNT" => methods.count.to_s,
    "THE_CONSTRUCTORS" => class_desc.name == "class" ?
    class_desc.get_elements("constructor").map{|i| i.constructor_definition(params[:name])}.join("\n\n") : "",
    "THE_METHODS" => methods.map{|i| i.method_definition}.join("\n\n")
  }
end

#get_class_or_interface(klass, force = false) ⇒ Object

get_class_or_interface: Opens the xml file and locates the specified class.

Aborts if the class is not found or if it is not available for
all api levels


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/ruboto/util/build.rb', line 30

def get_class_or_interface(klass, force=false)
  element = verify_api.find_class_or_interface(klass, "either")

  abort "ERROR: #{klass} not found" unless element

  unless force
    abort "#{klass} not available in minSdkVersion, added in #{element.attribute('api_added')}; use --force to create it" if
    element.attribute('api_added') and element.attribute('api_added').to_i > verify_min_sdk.to_i
    abort "#{klass} deprecated for targetSdkVersion, deprecatrd in #{element.attribute('deprecated')}; use --force to create it" if
    element.attribute('deprecated') and element.attribute('deprecated').to_i <= verify_target_sdk.to_i
  end

  abort "#{klass} removed for targetSdkVersion, removed in #{element.attribute('api_removed')}" if
  element.attribute('api_removed') and element.attribute('api_removed').to_i <= verify_target_sdk.to_i

  element
end