Compiling Flex apps with external swc libs and RSLs using ruby and rake

Posted by Tim Connor Sat, 08 Aug 2009 21:40:00 GMT

At work I maintain a number of flex projects, some of which are dynamically modified based on the results of slicing up SVG maps. As such, it is far easier to have a rake task do the compiling, rather than recompiling each one by hand, in Flex Builder.

Since there are a range of different projects that share some library code, I had to figure out how to compile them against an external swc, ideally loaded as an RSL for space savings and a couple other benefits. I hadn’t seen many full fleshed out examples of this, so I thought I should share.

Below is a stripped down version of the code that is called from rake; I cut out stuff specific to the work projects. I also made a flex ruby compiler gist so that it can be found on github and modified there.

module FlexCompiler
  COMPILER = "/Applications/Adobe\\ Flex\\ Builder\\ 3/sdks/3.2.0/bin/mxmlc"
  FRAMEWORK_PARAM = "-runtime-shared-library-path=/Applications/Adobe\\ Flex\\ Builder\\ 3/sdks/3.2.0/frameworks/libs/framework.swc,framework_3.2.0.3958.swz,,framework_3.2.0.3958.swf"
  COMPONENTS_PARAM = "-runtime-shared-library-path=vendor/flex/components/bin/components.swc,components.swf"
  DEFAULT_FLAGS = "--warnings=true --strict=true --debug=false" 
  
  def self.compile_swf(project)
    puts "compiling #{project}"
    project_path = "vendor/flex/#{project}/src/#{project}"
    compile_cmd = "#{COMPILER} #{DEFAULT_FLAGS} #{FRAMEWORK_PARAM} #{COMPONENTS_PARAM} -file-specs #{project_path}.mxml"
    #puts compile_cmd

    `#{compile_cmd}`
   `mv #{project_path}.swf public/flash/#{project}.swf`
  end
  
  def self.optimize_swc(library="components")
    `unzip vendor/flex/#{library}/bin/#{library}.swc -d vendor/flex/#{library}/bin/unzip`
    `optimizer -keep-as3-metadata="Bindable,Managed,ChangeEvent,NonCommittingChangeEvent,Transient" -input=vendor/flex/#{library}/bin/unzip/library.swf -output=public/flash/#{library}.swf`
    `rm -rf vendor/flex/#{library}/bin/unzip`
  end
 
end

One thing to beware of: make sure your various libraries (.swcs) externally link the framework rsl’s, otherwise they will be a couple 100k bigger with the duplication. By default in flex, libraries merge the framework in, which is counter-productive if you’ve taken steps to dynamically link it in your app.

Calling (invoking) rails rake tasks from within ruby, for testing, try 2 3

Posted by Tim Connor Thu, 21 Feb 2008 21:48:00 GMT

Yesterday I wrote a post on capturing the output of rake from a ruby call using backticks, because I wanted to do so in a test. Well, I had Date.today stubbed out, but got lazy and used yesterday’s date, so of course when I come in today the test fails. In the light of a new day my problem was obvious. If you call rake from a sub-shell, say via ``, of course your mocking will not exist in that process. So today, I had Another Wonderful Opportunity for Learning (there are acronyms for this that use a different word than wonderful): a chance to do it right.

It took a little digging to figure out how to get this to work right with the built-in rails tasks, so here you go:


require ‘rake’
require ‘rake/rdoctask’
require ‘rake/testtask’
require ‘tasks/rails’

def capture_stdout
s = StringIO.new
oldstdout = $stdout
$stdout = s
yield
s.string
ensure
$stdout = oldstdout
end

Rake.application.rake_require ‘../../lib/tasks/metric_fetcher’
results = capture_stdout {Rake.application[‘metric_fetcher’].invoke}

I liberated capture_stdout from the rake tests themselves. In retrospect, I should have just looked there first. As TDD and especially BDD get even more widespread the tests are often the easiest place to look for good examples of usage.

Capturing a system call in ruby with backticks, while setting an environment variable 1

Posted by Tim Connor Wed, 20 Feb 2008 18:26:00 GMT

As you may know system() and `` both make system calls in ruby, but the second one captures the STDOUT for you, essentially, which is handy sometimes, like when testing. They don’t necessarily both do this by just a straight call to the commandline, but various internal utilities that make such thing possible in Windows too, for instance.

Well the problem with this is it can mess with your setting of an ENV as a precursor to your command. For instance, this is valid on my platform:


RAILS_ENV=test rake metric_fetcher

and works via system():

system(“RAILS_ENV=test rake metric_fetcher”)

but chokes in backticks, probably due to the aforementioned jiggering around for Windows compat:

`RAILS_ENV=test rake metric_fetcher`

Now you generally can just move the command back to the beginning of the line:

`rake RAILS_ENV=test metric_fetcher`

but if for some bizarre reason that doesn’t work for you (it’s probably something else going, wrong, though, to be honest) you can do this:

ENV[‘RAILS_ENV’]=‘test’; `rake metric_fetcher`

So ultimately, I can do this hacky wonder:


assert `rake RAILS_ENV=test metric_fetcher`.empty?

if my rake task succeeds silently and fails noisily (which is a useful characteristic for cron’ed tasks).

Thanks to Defiler and ocotpod for proving to me I really did have my head up my ass and that all but the leading env var in backticks form should work as expected.(fixture set-up issues as usual).

Addendum And if you are calling rake like this in a test and getting odd problems – consider turning transaction fixtures off.

bash command completion for rake

Posted by Tim Connor Wed, 10 Oct 2007 03:29:00 GMT

I’ve written about improved bash completion in OS X before, but when setting up a iMac at my new job (more on that later), I couldn’t recall what I did for tab completion of rake tasks (which is really nice to have if you do much rails work). This time around, I just dropped Lee Marlow’s Rake Command Completion Using Rake into a scripts folder in my home directory, named it rake-completion.rb, and added


complete -C /Users/timconnor/scripts/rake-completion.rb -o default rake

into my .profile (or .bashrc or .bash_login, etc).

If you use one of the ruby completion scripts (like Lee’s) make sure not to drop it in your bash_completion auto-added folder (/opt/local/etc/bash_completion.d/) as that will choke, expecting a bash script, instead of a ruby one.

Backing up or transfering your data via YAML 4

Posted by Tim Connor Mon, 26 Mar 2007 21:27:00 GMT

Thanks to http://snippets.dzone.com/tag/fixtures. No warranties and no guarantees it’ll work on your full DB. I’m just using it for transferring around my starting data during dev.

Yes, I know part of this can be done with db:fixtures:load – but I don’t want to use ‘tests/fixtures’

lib/tasks/fixtures.rake


namespace :db do
namespace :YAML do
desc ‘Create YAML backup fixtures’
task :backup => :environment do
sql = “SELECT * FROM %s”
skip_tables = [“schema_info”, “sessions”]
ActiveRecord::Base.establish_connection
tables = ENV[‘FIXTURES’] ? ENV[‘FIXTURES’].split(/,/) : ActiveRecord::Base.connection.tables – skip_tables
tables.each do |table_name|
i = “000”
File.open(“#{RAILS_ROOT}/db/fixtures/#{table_name}.yml”, ‘w’) do |file|
data = ActiveRecord::Base.connection.select_all(sql % table_name)
file.write data.inject({}) { |hash, record|
hash[“#{table_name}_#{i.succ!}”] = record
hash
}.to_yaml
end
end
end

desc “Load db/fixtures in fixtures_load_order” task :restore => :environment do ActiveRecord::Base.establish_connection require ‘active_record/fixtures’ Fixtures.create_fixtures(“db/fixtures”, ActiveRecord::Base.configurations[:fixtures_load_order]) puts "Loaded these fixtures: " + ActiveRecord::Base.configurations[:fixtures_load_order].collect { |f| f.to_s }.join(’, ’) end end

end

config/environments.rb


ActiveRecord::Base.configurations[:fixtures_load_order] = [
:users,
:locations,
:reports,
:conditions
]