Steven Xu

Month

December 2012

1 post

Autocomplete addEventListener constants in AS3

I’ve been having some difficulty getting Flash Builder to autocomplete event type constants on addEventListener. Seems like you need to do each of the following to get it to work properly:

1. Put the event meta tag above the dispatching class
[Event(name="foo",type="pkg.events.Constants")]
class SomethingThatDispatchesFoo extends EventDispatcher {

Be sure not to accidentally put it on top of the constructor.

2. Make sure the type corresponds to the event class

AS3 gives you the handy CTRL+click functionality on the type string. Unfortunately, it doesn’t autoupdate it during a normal refactor.

If you don’t do this, AS3 will autocomplete it but only as a string.

3. Use double quotes everywhere

The [Event] metatag won’t work at all with single quotes. Also, in code, if you define your string constant with single quotes, constant resolution will not work.

class Constants {
  public static const FOO:String = 'foo';
}

// autocomplete will suggest 'foo'

You must use double quotes.

class Constants {
  public static const FOO:String = "foo"
}

// autocomplete will suggest Constants.FOO
Some things that you don’t have to do for it to work
  • Your event constant name in code (e.g., pkg.events.Constants.FOO) does not have to bear any resemblance to the string value it references. You can have public static const FOO = "bar" and it will work just great.
  • It doesn’t appear that you need to recompile to have FB pick up on the new constants.
Dec 7, 2012

February 2012

2 posts

Array#uniq in Ruby 1.8.7

On github: https://gist.github.com/1905081

class Equal
  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def inspect
    @name
  end

  def hash
    puts "#{name}: hash"
    super
  end

  def eql?(co)
    puts "#{name}: eql? against #{co.name}"
    super
  end

  def ==(co)
    puts "#{name}: == against #{co.name}"
    super
  end
end

EqualA = Equal.new('EqualA')
EqualB = Equal.new('EqualB')
EqualC = Equal.new('EqualC')

puts

def run(cmd)
  puts "~~ #{cmd} ~~"
  puts eval(cmd).inspect
  puts
end

run '[EqualA, EqualB].uniq'
run '[EqualA, EqualB, EqualC].uniq'

class EqualHash < Equal
  def hash
    puts "#{name}: hash"
    1000
  end
end

EqualHashA = EqualHash.new('EqualHashA')
EqualHashB = EqualHash.new('EqualHashB')
EqualHashC = EqualHash.new('EqualHashC')

puts

run '[EqualHashA, EqualHashB].uniq'
run '[EqualHashA, EqualHashB, EqualHashC].uniq'

class EqualHashAndEql < EqualHash
  def eql?(co)
    puts "#{name}: eql? against #{co.name}"
    true
  end
end

EqualHashAndEqlA = EqualHashAndEql.new('EqualHashAndEqlA')
EqualHashAndEqlB = EqualHashAndEql.new('EqualHashAndEqlB')
EqualHashAndEqlC = EqualHashAndEql.new('EqualHashAndEqlC')
EqualHashAndEqlD = EqualHashAndEql.new('EqualHashAndEqlD')

puts

run '[EqualHashAndEqlA, EqualHashAndEqlB].uniq'
run '[EqualHashAndEqlA, EqualHashAndEqlB, EqualHashAndEqlC].uniq'
run '[EqualHashAndEqlA, EqualHashAndEqlB, EqualHashAndEqlC, EqualHashAndEqlD].uniq'

Equal is little more than a wrapper to Object to make things prettier. EqualHash is a subclass of Equal whose instances always return 1000 for #hash. EqualHashAndEql is a subclass of EqualHash whose instances always return true for #eql?.

Here’s the output with commentary:

~~ [EqualA, EqualB].uniq ~~
EqualA: hash
EqualB: hash
[EqualA, EqualB]

~~ [EqualA, EqualB, EqualC].uniq ~~
EqualA: hash
EqualB: hash
EqualC: hash
[EqualA, EqualB, EqualC]

#uniq internally calls #hash on each element, realizes they’re different and allows both in the resulting array.

~~ [EqualHashA, EqualHashB].uniq ~~
EqualHashA: hash
EqualHashB: hash
EqualHashB: eql? against EqualHashA
[EqualHashA, EqualHashB]

~~ [EqualHashA, EqualHashB, EqualHashC].uniq ~~
EqualHashA: hash
EqualHashB: hash
EqualHashB: eql? against EqualHashA
EqualHashC: hash
EqualHashC: eql? against EqualHashB
EqualHashC: eql? against EqualHashA
[EqualHashA, EqualHashB, EqualHashC]

#uniq sees the hash collisions and falls back to calling #eql? in a n^2 loop.

~~ [EqualHashAndEqlA, EqualHashAndEqlB].uniq ~~
EqualHashAndEqlA: hash
EqualHashAndEqlB: hash
EqualHashAndEqlB: eql? against EqualHashAndEqlA
EqualHashAndEqlA: hash
EqualHashAndEqlB: hash
[EqualHashAndEqlA]

~~ [EqualHashAndEqlA, EqualHashAndEqlB, EqualHashAndEqlC].uniq ~~
EqualHashAndEqlA: hash
EqualHashAndEqlB: hash
EqualHashAndEqlB: eql? against EqualHashAndEqlA
EqualHashAndEqlC: hash
EqualHashAndEqlC: eql? against EqualHashAndEqlA
EqualHashAndEqlA: hash
EqualHashAndEqlB: hash
EqualHashAndEqlC: hash
[EqualHashAndEqlA]

~~ [EqualHashAndEqlA, EqualHashAndEqlB, EqualHashAndEqlC, EqualHashAndEqlD].uniq ~~
EqualHashAndEqlA: hash
EqualHashAndEqlB: hash
EqualHashAndEqlB: eql? against EqualHashAndEqlA
EqualHashAndEqlC: hash
EqualHashAndEqlC: eql? against EqualHashAndEqlA
EqualHashAndEqlD: hash
EqualHashAndEqlD: eql? against EqualHashAndEqlA
EqualHashAndEqlA: hash
EqualHashAndEqlB: hash
EqualHashAndEqlC: hash
EqualHashAndEqlD: hash
[EqualHashAndEqlA]

Same as above, except that because #eql? returns true, B, C, and D are not added to the intermediate resulting array. I’m not entirely sure why #hash is called again once everything is done though.

Feb 24, 2012
Autoloading in Rails 3

Rails 3 by default adds these to the autoload paths:

app/*
vendor/plugins/*/lib
vendor/plugins/*/app/*

In addition, gems, when they are defined as Rails engines/railties, get each directory in app added to the autoload path.

Notable exceptions: Rails does not automatically add its own lib directory or the lib directories of any plugins to the load path.

Feb 1, 2012

September 2011

1 post

Asset fallback paths in Rails 3.1

Many things can cause your production asset paths to change. When that happens, your previous assets just stop working at all. Moreover, it seems like it would make sense for the bare asset path (without the md5 postfix) should just point to the most recent version of the asset. This little tidbit should take care of all of that.

Myapp::Application.routes.draw do
  match 'assets/:id.:format' => 'assets#show'
end

class AssetsController < ApplicationController
  def show
    asset_without_digest = "#{params[:id].gsub /-[0-9a-f]{32}$/, ''}.#{params[:format]}"
    new_path = ActionView::Base.new.image_path(asset_without_digest)
    if url_for(params).include? new_path
      head 404
    else
      redirect_to new_path, :status => 301
    end
  end
end
Sep 11, 2011

March 2011

1 post

Mar 16, 2011
Next page →
2011 2012
  • January
  • February 2
  • March
  • April
  • May
  • June
  • July
  • August
  • September
  • October
  • November
  • December 1
2011 2012
  • January
  • February
  • March 1
  • April
  • May
  • June
  • July
  • August
  • September 1
  • October
  • November
  • December