Wolfmans Howlings

A programmers Blog about Ruby, Rails and a few other issues

Ruby 1.8.6 on Openmoko Freerunner

Posted by Jim Morris Mon, 11 Aug 2008 06:09:00 GMT

I finally got around to building ruby 1.8.6 for my FR. I modified the ruby bitbake files that I found in the Mokomakefile openembedded directory. I am not sure how one actually is meant to do this, as the OE site is down and the docs don't explain it. So I just replcaed the 1.8.5 ones with the 1.8.6 ones. I also managed to fix a bug in the 1.8.5 BB recipe that was causing socket to not build.

I also got the ruby dbus library to work, although I don't know what to do with it yet :)

So until I figure out how you are meant to add a new version to OE, I have put the ipk here.

If you want ruby 1.9 you can find it here

To install it just ssh into your FR and type

> wget http://blog.wolfman.com/files/ruby_1.8.6-p287-r1_armv4t.ipk
> opkg install ruby_1.8.6-p287-r1_armv4t.ipk

If you want to install gem then you need to ssh into the FR and do this...

> wget http://rubyforge.org/frs/download.php/38646/rubygems-1.2.0.tgz
> tar xzvf rubygems-1.2.0.tgz
> cd rubygems-1.2.0
> ruby setup.rb --no-rdoc --no-ri

I recommend you do the no doc and no ri otherwise it takes forever.

As for dbus...

> wget https://trac.luon.net/data/ruby-dbus/releases/ruby-dbus-0.2.1.tar.gz
> tar xzvf ruby-dbus-0.2.1.tar.gz
> cd ruby-dbus-0.2.1
> ruby setup.rb config
> ruby setup.rb setup
> ruby setup.rb install

look in the examples to see how to use it, I tries this...

> ruby examples/utils/listnames.rb --system
    org.freedesktop.DBus
    :1.3
    :1.4
    org.freedesktop.Avahi
    :1.0
    org.bluez
    :1.1
    :1.6
    :1.2
    org.freedesktop.Hal

So it seems to work.

Let me know what you do with it.

I also built jove, my favorite mini-emacs editor, this is just an executable just copy to /usr/bin Use instead of vi or nano.

Posted in  | Tags ,  | 1 comment | no trackbacks

JEdit Ruby/Rails Snippets or superabbrevs

Posted by Jim Morris Sat, 25 Nov 2006 03:05:00 GMT

I imported the rest of the Textmate ruby and rails snippets I had to combine them into the one ruby file though.

I have added about 80 new ones to the existing ones by Scott Becker that I found here

The list of snippets I now have is at the end of this post, note I did change the abbreviation for some of the assertions they all now start with as so I can search for them faster with my select_superabbrevs macro described in the previous post.

download the new snippets from here unzip and replace the ruby file in the .jedit/SuperAbbrevs directory with the one in this zip archive.

You need the Beta version of SuperAbbrevs to use this from here

Super Abbreviations for the ruby mode

--------------------------------------- : --------------------------------------
:${1:key} => ${2:"value"}$end

-------------------------------------- all -------------------------------------
all? { |${1:e}| $end }

-------------------------------------- am --------------------------------------
alias_method :${1:new_name}, :${2:old_name}

-------------------------------------- any -------------------------------------
any? { |${1:e}| $end }

-------------------------------------- app -------------------------------------
if __FILE__ == \$PROGRAM_NAME
    $end
end

-------------------------------------- ase -------------------------------------
assert_equal ${1:value}, @${2:thing}.${3:attr}$end

------------------------------------- asid -------------------------------------
assert_in_delta(${1:expected_float}, ${2:actual_float}, ${3:2 ** -20})

------------------------------------- asio -------------------------------------
assert_instance_of(${1:ExpectedClass}, ${2:actual_instance})$end

------------------------------------- asko -------------------------------------
assert_kind_of ${1:Class}, @${2:thing}$end

-------------------------------------- asm -------------------------------------
assert_match(/${1:expected_pattern}/, ${2:actual_string})

-------------------------------------- asn -------------------------------------
assert_nil(${1:instance})$end

------------------------------------- asne -------------------------------------
assert_not_equal(${1:unexpected}, ${2:actual})

------------------------------------- asnm -------------------------------------
assert_no_match(/${1:unexpected_pattern}/, ${2:actual_string})

------------------------------------- asnn -------------------------------------
assert_not_nil ${1:true}$end

------------------------------------- asnr -------------------------------------
assert_nothing_raised(${1:Exception}) { $end }

------------------------------------- asns -------------------------------------
assert_not_same(${1:unexpected}, ${2:actual})$end

------------------------------------- asnt -------------------------------------
assert_nothing_thrown { $end }

-------------------------------------- aso -------------------------------------
assert_operator(${1:left}, :${2:operator}, ${3:right})

-------------------------------------- asr -------------------------------------
assert_raise(${1:ActiveRecord::RecordNotFound}) { ${2:Class}.find(@${3:thing}.${4:id}) }$end

------------------------------------- asrar ------------------------------------
assert_raise(${1:ActiveRecord::RecordNotFound}) { ${2:Class}.find(@${3:thing}.${4:id}) }

------------------------------------- asre -------------------------------------
assert_response :${1:success}$end

------------------------------------- asrt -------------------------------------
assert_redirected_to :action => "${1:index}"$end

-------------------------------------- ass -------------------------------------
assert(${1:test}, "${2:Failure message.}")

------------------------------------- assm -------------------------------------
assert_same(${1:expected}, ${2:actual})$end

-------------------------------------- ast -------------------------------------
assert_throws(:${1:expected}) { $end }

-------------------------------------- bt --------------------------------------
belongs_to :${1:object}, :class_name => "${2:ClassName}", :foreign_key => "${3:foreign_key}_id"$end

------------------------------------- case -------------------------------------
case ${1:object}
when ${2:condition}
    $end
end

-------------------------------------- cl --------------------------------------
classify { |${1:e}| $end }

------------------------------------- clafn ------------------------------------
split("::").inject(Object) { |par, const| par.const_get(const) }

------------------------------------- class ------------------------------------
class ${1:ClassName}
    $end
end

-------------------------------------- col -------------------------------------
collect { |${1:e}| $end }

------------------------------------ collect -----------------------------------
collect { |${1:element}| ${1:element}.$2 }$end

------------------------------------- Comp -------------------------------------
include Comparable

def <=>(other)
    $end
end

-------------------------------------- dee -------------------------------------
Marshal.load(Marshal.dump(${1:obj_to_copy}))

-------------------------------------- def -------------------------------------
def ${1:method_name}
  $end
end

------------------------------------- defd -------------------------------------
def_delegator :${1:@del_obj}, :${2:del_meth}, :${3:new_name}

------------------------------------- defds ------------------------------------
def_delegators :${1:@del_obj}, :${2:del_methods}

------------------------------------- defs -------------------------------------
def self.${1:class_method_name}
    $end
end

------------------------------------- deft -------------------------------------
def test_${1:case_name}
    $end
end

-------------------------------------- det -------------------------------------
detect { |${1:e}| $end }

-------------------------------------- do --------------------------------------
do
    $end
end

-------------------------------------- doo -------------------------------------
do |${1:object}|
    $end
end

-------------------------------------- ea --------------------------------------
each { |${1:e}| $end }

-------------------------------------- eab -------------------------------------
each_byte { |${1:byte}| $end }

-------------------------------------- eac -------------------------------------
each_char { |${1:chr}| $end }

------------------------------------- each -------------------------------------
each { |${1:element}| ${1:element}.$end }

-------------------------------- each_with_index -------------------------------
each_with_index { |${1:element}, ${2:idx}| ${1:element}.$end }

-------------------------------------- eai -------------------------------------
each_index { |${1:i}| $end }

-------------------------------------- eak -------------------------------------
each_key { |${1:key}| $end }

-------------------------------------- eal -------------------------------------
each_line$1 { |${2:line}| $end }

-------------------------------------- eap -------------------------------------
each_pair { |${1:name}, ${2:val}| $end }

------------------------------------- easl -------------------------------------
each_slice(${1:2}) { |${2:group}| $end }

-------------------------------------- eav -------------------------------------
each_value { |${1:val}| $end }

------------------------------------- eawi -------------------------------------
each_with_index { |${1:e}, ${2:i}| $end }

------------------------------------- Enum -------------------------------------
include Enumerable

def each(&block)
    $end
end

-------------------------------------- fin -------------------------------------
find { |${1:e}| $end }

------------------------------------- fina -------------------------------------
find_all { |${1:e}| $end }

-------------------------------------- fl --------------------------------------
flunk("${1:Failure message.}")

------------------------------------- flao -------------------------------------
inject(Array.new) { |${1:arr}, ${2:a}| ${1:arr}.push(*${2:a}) }

------------------------------------- flash ------------------------------------
flash[:${1:notice}] = "${2:Successfully created...}"$end

------------------------------------- forin ------------------------------------
for ${1:element} in ${2:collection}
    ${1:element}.$3
end$end

------------------------------------- Forw -------------------------------------
extend Forwardable

-------------------------------------- gre -------------------------------------
grep(${1:/${2:pattern}/}) { |${3:match}| $end }

------------------------------------- Hash -------------------------------------
Hash.new { |${1:hash}, ${2:key}| ${1:hash}[${2:key}] = $end }

-------------------------------------- hm --------------------------------------
has_many :${1:objects}, :class_name => "${2:ClassName}", :foreign_key => "${3:foreign_key}_id"$end

-------------------------------------- ho --------------------------------------
has_one :${1:object}, :class_name => "${2:ClassName}", :foreign_key => "${3:foreign_key}_id"$end

-------------------------------------- if --------------------------------------
if ${1:condition}
    $end
end

-------------------------------------- ife -------------------------------------
if ${1:condition}
    $2
else
    $3
end

-------------------------------------- inj -------------------------------------
inject(${1:init}) { |${2:mem}, ${3:var}| $end }

------------------------------------ inject ------------------------------------
inject(${1:object}) { |${2:injection}, ${3:element}| $4 }$end

------------------------------------- logi -------------------------------------
logger.info "${1:Current value is...}"$end

-------------------------------------- mac -------------------------------------
add_column :${1:table_name}, :${2:column_name}, :${3:string}$end

-------------------------------------- mai -------------------------------------
add_index :${1:table_name},[:${2:column_name}], :name => "${2:column_name}_index"$end

-------------------------------------- map -------------------------------------
map { |${1:e}| $end }

------------------------------------- mapwi ------------------------------------
enum_with_index.map { |${1:e}, ${2:i}| $end }

-------------------------------------- max -------------------------------------
max { |a, b| $end }

-------------------------------------- mcc -------------------------------------
change_column :${1:table_name}, :${2:column_name}, :${3:string}, ${4:default => 1}$end

-------------------------------------- mct -------------------------------------
create_table :${1:table_name} do |t|
  $2
end

-------------------------------------- Md --------------------------------------
File.open(${1:"${2:path/to/file}.dump"}, "w") { |${3:file}| Marshal.dump(${4:obj}, ${3:file}) }

-------------------------------------- mdt -------------------------------------
drop_table :${1:table_name}$end

-------------------------------------- mex -------------------------------------
execute "$1"$end

-------------------------------------- min -------------------------------------
min { |a, b| $end }

-------------------------------------- mm --------------------------------------
def method_missing(meth, *args, &block)
    $end
end

-------------------------------------- mnc -------------------------------------
rename_column :${1:table_name}, :${2:column_name}, :${3:new_column}$end

-------------------------------------- mod -------------------------------------
module ${1:ModuleName}
    module_function

    $end
end

-------------------------------------- mrc -------------------------------------
remove_column :${1:table_name}, :${2:column_name}$end

-------------------------------------- mri -------------------------------------
remove_index :${1:table_name}, :${2:column_name}$end

-------------------------------------- mtc -------------------------------------
t.column :${1:column_name}, :${2:string}$end

--------------------------------------- p --------------------------------------
params[:${1:id}]$end

-------------------------------------- par -------------------------------------
partition { |${1:e}| $end }

--------------------------------------- r --------------------------------------
attr_reader :${1:attr_names}

-------------------------------------- ra --------------------------------------
render :action => "${1:action}"$end

-------------------------------------- ral -------------------------------------
render :action => "${1:action}", :layout => "${2:layoutname}"$end

-------------------------------------- ran -------------------------------------
sort_by { rand }

-------------------------------------- rb --------------------------------------
#!/usr/bin/env ruby -w



------------------------------------- rcea -------------------------------------
render_component :action => "${1:index}"$end

------------------------------------- rcec -------------------------------------
render_component :controller => "${1:items}"$end

------------------------------------- rceca ------------------------------------
render_component :controller => "${1:items}", :action => "${2:index}"$end

-------------------------------------- rea -------------------------------------
redirect_to :action => "${1:index}"$end

------------------------------------- reai -------------------------------------
redirect_to :action => "${1:show}", :id => ${2:@item}$end

-------------------------------------- rec -------------------------------------
redirect_to :controller => "${1:items}"$end

------------------------------------- reca -------------------------------------
redirect_to :controller => "${1:items}", :action => "${2:list}"$end

------------------------------------- recai ------------------------------------
redirect_to :controller => "${1:items}", :action => "${2:show}", :id => ${3:@item}$end

-------------------------------------- rej -------------------------------------
reject { |${1:e}| $end }

------------------------------------ reject ------------------------------------
reject { |${1:element}| ${1:element}.$end }

-------------------------------------- req -------------------------------------
require "$end"

------------------------------------- reve -------------------------------------
reverse_each { |${1:e}| $end }

-------------------------------------- rf --------------------------------------
render :file => "${1:filepath}"$end

-------------------------------------- rfu -------------------------------------
render :file => "${1:filepath}", :use_full_path => ${2:false}$end

-------------------------------------- ri --------------------------------------
render :inline => "${1:<%= 'hello' %>}"$end

-------------------------------------- ril -------------------------------------
render :inline => "${1:<%= 'hello' %>}", :locals => { ${2::name} => "${3:value}"$4 }$end

-------------------------------------- rit -------------------------------------
render :inline => "${1:<%= 'hello' %>}", :type => ${2::rxml}$end

-------------------------------------- rl --------------------------------------
render :layout => "${1:layoutname}"$end

-------------------------------------- rn --------------------------------------
render :nothing => ${1:true}$end

-------------------------------------- rns -------------------------------------
render :nothing => ${1:true}, :status => ${2:401}$end

-------------------------------------- rp --------------------------------------
render :partial => "${1:item}"$end

-------------------------------------- rpc -------------------------------------
render :partial => "${1:item}", :collection => ${2:items}$end

-------------------------------------- rpl -------------------------------------
render :partial => "${1:item}", :locals => { :${2:name} => "${3:value}"$4 }$end

-------------------------------------- rpo -------------------------------------
render :partial => "${1:item}", :object => ${2:object}$end

-------------------------------------- rps -------------------------------------
render :partial => "${1:item}", :status => ${2:500}$end

-------------------------------------- rt --------------------------------------
render :text => "${1:text to render...}"$end

-------------------------------------- rtl -------------------------------------
render :text => "${1:text to render...}", :layout => "${2:layoutname}"$end

------------------------------------- rtlt -------------------------------------
render :text => "${1:text to render...}", :layout => ${2:true}$end

-------------------------------------- rts -------------------------------------
render :text => "${1:text to render...}", :status => ${2:401}$end

-------------------------------------- rw --------------------------------------
attr_accessor :${1:attr_names}

--------------------------------------- s --------------------------------------
session[:${1:user}]$end

-------------------------------------- sca -------------------------------------
scan(/${1:pattern}/) { |${2:match}| $end }

-------------------------------------- sel -------------------------------------
select { |${1:e}| $end }

------------------------------------ select ------------------------------------
select { |${1:element}| ${1:element}.$2 }$end

-------------------------------------- sor -------------------------------------
sort { |a, b| $end }

------------------------------------- sorb -------------------------------------
sort_by { |${1:e}| $end }

-------------------------------------- tc --------------------------------------
require "test/unit"

require "${1:library_file_name}"

deli    delete_if { |${1:e}| $end }

-------------------------------------- ts --------------------------------------
require "test/unit"

require "tc_${1:test_case_file}"
require "tc_${2:test_case_file}"

-------------------------------------- uni -------------------------------------
ARGF.each_line$1 do |${2:line}|
    $end
end

------------------------------------ unless ------------------------------------
unless ${1:condition}
    $end
end

------------------------------------- usai -------------------------------------
if ARGV.$1
  puts "Usage:  #{\$PROGRAM_NAME} ${2:ARGS_GO_HERE}"
  exit
end

------------------------------------- usau -------------------------------------
unless ARGV.$1
  puts "Usage:  #{\$PROGRAM_NAME} ${2:ARGS_GO_HERE}"
  exit
end

-------------------------------------- va --------------------------------------
validates_associated :${1:attribute}, :on => "${2:create}"$end

------------------------------------- vaif -------------------------------------
validates_associated :${1:attribute}, :on => "${2:create}", :if => proc { |obj| ${3:obj.condition?} }$end

-------------------------------------- vc --------------------------------------
validates_confirmation_of :${1:attribute}, :on => "${2:create}", :message => "${3:should match confirmation}"$end

------------------------------------- vcif -------------------------------------
validates_confirmation_of :${1:attribute}, :on => "${2:create}", :message => "${3:should match confirmation}", :if => proc { |obj| ${4:obj.condition?} }$end

-------------------------------------- ve --------------------------------------
validates_exclusion_of :${1:attribute}, :in => ${2:enumerable}, :on => "${3:create}", :message => "${4:is not allowed}"$end

------------------------------------- veif -------------------------------------
validates_exclusion_of :${1:attribute}, :in => ${2:enumerable}, :on => "${3:create}", :message => "${4:is not allowed}", :if => proc { |obj| ${5:obj.condition?} }$end

------------------------------------ verify ------------------------------------
verify :only => [:$1], :method => :post, :render => {:status => 500, :text => "use HTTP-POST"}$end

------------------------------------ verifyr -----------------------------------
verify :only => [:$1], :session => :user, :params => :id, :redirect_to => {:action => '${2:index}'}$end

------------------------------------- vlen -------------------------------------
validates_length_of ${1::name}, :maximum=>${2:10}, :message=>"${3:less than %d if you don't mind}"

-------------------------------------- vp --------------------------------------
validates_presence_of :${1:attribute}, :on => "${2:create}", :message => "${3:must be present}"$end

------------------------------------- vpif -------------------------------------
validates_presence_of :${1:attribute}, :on => "${2:create}", :message => "${3:must be present}", :if => proc { |obj| ${4:obj.condition?} }$end

-------------------------------------- vu --------------------------------------
validates_uniqueness_of :${1:attribute}, :on => "${2:create}", :message => "${3:must be unique}"$end

------------------------------------- vuif -------------------------------------
validates_uniqueness_of :${1:attribute}, :on => "${2:create}", :message => "${3:must be unique}", :if => proc { |obj| ${4:obj.condition?} }$end

--------------------------------------- w --------------------------------------
attr_writer :${1:attr_names}

------------------------------------- when -------------------------------------
when ${1:condition}
    $end

------------------------------------- ydump ------------------------------------
File.open(${1:"${2:path/to/file}.yaml"}, "w") { |${3:file}| YAML.dump(${4:obj}, ${3:file}) }

------------------------------------- yload ------------------------------------
File.open(${1:"${2:path/to/file}.yaml"}) { |${3:file}| YAML.load(${3:file}) }

-------------------------------------- zip -------------------------------------
zip(${1:enums}) { |${2:row}| $end }

Posted in , ,  | Tags , , , ,  | 8 comments | no trackbacks

JEdit - Textmate for the rest of us?

Posted by Jim Morris Wed, 22 Nov 2006 07:20:07 GMT

OK after expounding on how much I like Epsilon as an editor, I finally hit a wall with it. I wanted tabs of the currently open files, and it simply does not provide that facility yet. (I know all modern editors do!). On X11 (IE Linux and OS/X) Epsilon is not really a graphical app, it does open an X11 window, but within it most dialogs and lists (like buffer lists etc) are text, a little like a curses app. The advantage is it opens really fast, and loads huge files pretty fast. The downside is you don't get all those nice windowing facilities like movable pop-up windows, dialogs, trees and tabs!

So after hearing so much about JEdit, I bit the bullet and gave it a whirl. Following the instructions from a number of blogs (too numerous to mention) I installed it on my KUbuntu Linux box, with all the plugins people recommend, and of course the Ruby plugin and SupperAbbrevs (The beta version), so I have my snippets!

Being used to an Emacs like editor I had to fuss around remapping all my keys (or at least some of them), then map the new plugins to reasonable key-bindings (called shortcuts in JEdit lingo).

I have to say I am pretty impressed, it does everything I want (or almost). It has a plugin for tabs, it has a project manager, and HTML/XML modes. The Ruby mode is pretty good, modeled after Textmate.

So the things that were missing that I had become accustomed to were.

  • Expanding #{} in a string when you type # - Wrote a macro to do that
  • Being able to select a snippet (called abbreviation in the lingo) from a list rather than having to remember the abbreviation. - wrote a macro to do it
  • Some Emacs like behavior like control-K etc. - found it in the macros manager
  • Toggling between view and controller (and model) in a rails project - Wrote one, but found a better one in macros
  • Being able to use snippets (OK abbreviations!) from a different language mode. eg I'm in rhtml but I want an HTML abbreviation, or vice versa. - wrote a macro to do it
  • Running ruby scripts into a local buffer - the console plugin solved this
  • Running Focused Ruby Unit tests - wrote a macro to do it

So at first I thought I would have to hack the various plugins, but then I discovered the beanShell macros are extremely powerful, basically they are java syntax, but have full access to the JEdit internals and most of the plugins internals too. As Java is my second favorite language, this was a nice surprise. (You should guess by now Ruby is my current favorite language).

So I went about writing macros to fill in the gaps, to see if I could switch to JEdit.

As a side note I will not buy a Mac so I can use Textmate! as awesome as Textmate is, it is not enough to get me to switch, so I will get JEdit as close to it as I can, maybe even further. (I worked on a MacBook Pro Intel for 3+ months, and was not sold).

Yes JEdit actually has intellisense-like completion for Ruby. A previous blog entry of mine explained how I tried Komodo to get this, but it was not very good, however the JEdit version found in the latest RubyPlugin, works pretty well, I think it uses parsing from the JRuby project, so no surprise it works.

In addition it also has a pretty good ruby and rails help, that is linked to the autocomplete, it is missing a few rails entries, but is very handy. Features of this clever plugin are found here.

All this and JEdit is free!

Back to the macro writing.

The first hack, er I mean Macro, was to expand # to #{} when it is in a string. This was relatively easy, as shown below. I just has to make sure I was actually in a string, and take into account escaped quotes and escaped #. Anyway the macro works quite well, I think it would be better off in the RubyPlugin, but never mind.

It took me a while to think of beanshell as Java, I kept wanting to leave off ; and other scripting language things, but it really is Java, just scripted, very impressive language, I have no idea how they do it, if they compile on the fly or interpret, but it works, and you have full access to Swing, and as I have written many thousands of lines of Java/Swing code over the years, I was back in business. (It did take me a while to remember that stuff though as my Swing Feng was a few years old).

// Expand # to #{} if in quotes
boolean escaped() {
  pos= textArea.getCaretPosition();
  str= textArea.getText(pos-1, 1);
  return(str.equals("\\"));
}

boolean inQuotes() {
  cl= textArea.getCaretLine();
  str= textArea.getLineText(cl);
  pos= (textArea.getCaretPosition() - textArea.getLineStartOffset(cl))-1;
  cnt= 0;
  do{
    off= str.lastIndexOf("\"", pos);
    if(off < 0)
      break;
    else if(off == 0 || str.charAt(off-1) != '\\')
      cnt++;
    pos= off-1;
  }while(pos >= 0);
  return (cnt & 1) != 0;
}

if((buffer.getMode().getName().equals("ruby") || buffer.getMode().getName().equals("rhtml")) && inQuotes() && !escaped()){
  textArea.setSelectedText("#{}");
  textArea.goToPrevCharacter(false);
}else{
    textArea.setSelectedText("#");
}

The next one was recreating my Epsilon Hack that toggles between view and controller. I found a great starting macro which toggled between model and controller, so I just modified that a bit, using the same basic technique, and within a few hours I had my view/controller toggle. It may not be as robust as my Epsilon version, as it does a pretty naive search to find what method it is in, in the controller, but it seems to work. Of course, as with Textmates version, it only works if the rails naming conventions are followed. Download from here

UPDATE I have found a much better implementation with all the bells and whistles of the Textmate version here.

The big one was getting a list up to show the SupperAbbrevs snippets for any given mode, and selecting the one you want. This took a good part of a day, I had to study the SupperAbbrevs code, and I found a good starting point with a macro that lists abbreviations from the built-in JEdit abbreviations. I use a good part of that, and just changed it so you can select one of the abbreviations and use that to insert the snippet. I ran into a few quirks with JTable and selection, but that was because I was pretty rusty, I have solved those problems before, I had just forgotten how to.

So now I can type a portion or just one letter of an abbreviation, hit Alt-Space and I get a pop-up with all the abbreviations of the current mode, and the first one that matches what I have typed so far already selected. Hitting enter will insert that one, or I can select the one I want, and hit enter or click Expand, and it does its magic. I need this as I can never remember all those abbreviations, for all the rails and ruby snippets. (Not even Textmate can do that!) Of course I can still type in the whole abbreviation and hit TAB to get the quick expansion as before.

Now something that Textmate does that I like is you can click on an icon and you get a list of all the modes then you can select a snippet from any mode and insert it. I don't think macros will let you do exactly that, (I think that would require a plugin), but the next best thing is hitting Alt-Space with nothing in front of it, and I get a pop up. I can select the mode I want then the snippet from the table, and click insert, and it does the same thing. Just a few extra mouse clicks than Textmate, but close enough for me.

Now I just have to figure out how to contribute these macros to the Textmate community, the Wiki is closed to registered users only, and I got no reply when I tried to register.

I'll put all my macros here for now, until they register me. Then you will be able to download these macros from the nice MacroManager plugin they have in JEdit. So far there seems to be a plugin or macro for almost everything. The other macros are all available via the macroManager plugin, including the toggle between model and controller one. The Emacs macros are also available from the same utility.

I should say I am using the 4.2stable version of JEdit, I played with 4.3pre8 but it was throwing a lot of exceptions on the screen, although none fatal, but it did seem to be a little slower, I'll wait for it become more stable before trying again.

The RubyPlugin is available from the plugin manager, the latest version of superAbbrevs is not however, I got it from this link explained here

These were the most useful howtos I found ruby-rails-jedit, and jedit-for-ruby-rails-development.

but there are literally hundreds around.

Another idea taken from Textmate is a macro that runs the current Ruby Unit Test case, download from here. It will run a focused test only on the testcase the cursor is currently in.

Here is the download link for the biggest Macro I have done to date, it is the one that allows you to select a SuperAbbrev snippet.

Posted in , ,  | Tags , , ,  | 5 comments | no trackbacks

Epsilon Programmers Editor

Posted by Jim Morris Sun, 01 Oct 2006 00:20:00 GMT

I use Lugarus excellent Epsilon Editor for most of my programming editing needs, on Win32 and Linux.

(An exception is for Java programming where I use Eclipse).

I have spent some time writing extensions to Epsilon to handle Ruby and Rails programming, inspired mostly by Textmate on Mac/OSX, and Eclipse for Java. I tried using the Eclipse for Ruby, but I was very disappointed, also the developers have made some design decisions I can't live with (like no auto indent after opening braces etc).

I have tried Komodo Pro as described here.

OK the Epsilon editor is not free, it costs about $250 ($99 for an upgrade) which includes all platforms, and the license lets you use it on your Laptop and Desktop, in fact you can use any version of Epsilon on up to four computers you own. The result is a professional, solid, stable Editor, that is what you get when you pay for something. (This editor has been around at least 20 years, which is when I started using it on DOS!). In addition to running as an X Windows program and a console program on windows and Linux it also runs on Mac OS X, FreeBSD, OS/2 and DOS.

The Editor is an Emacs clone out of the box, it also has CUA and Brief emulations (well key bindings). The best feature IMHO is the fact you get most of the source code for the editor which is written in its own c-like language called eel. This makes it much easier to write extensions and customizations for the editor if you are familiar with C. (I never could wrap my brain around Lisp which is why I don't use GNU Emacs). It also runs in console mode as well as windows mode, which is useful if you have to login via ssh etc to edit files.

Seeing how every programmer has their own ideas of what an editor should do and its look and feel, easy customization is crucial.

The extensions I have written for Epsilon are all freely available, as are extensions written by other users. (Various language modes, template extensions, SCM extensions etc).

In the past I wrote a java help extension that tried to do context sensitive help, this worked OK but not as well as Eclipse.

Recently I wrote a bunch of extensions for Ruby and Rails, thanks to the ruby mode extension written by Timothy Byrd (available on Lugaru's download page) I was able to get syntax highlighting and formatting already done. I added some simple help extensions, a snippet facility (ala Textmate), and some convenience actions for Rails development. I also extended Timothy's ruby mode extension with something that completes the #{} when # is typed in a string. (I first saw this in Textmate and hated it, but it grew on me, until I had to have it on Linux). I have avoided the temptation to also do the automatic closing of { ( " etc that you find in Textmate because I still hate those, but they are easy to do using the same technique I used for #{}.

I've also added the ability to run the current buffer through the ruby interpreter and show the results in a pop up window, also to run a specific unit test if the file is a Ruby test case.

The key strokes any command uses is easily modified, as well as the colors used for syntax highlighting.

The version of ruby_mode.e on Lugarus site does not currently have the latest changes I have made, so it can be downloaded from the link below...

The other extensions can also be downloaded from my site...

These can be installed by copying them to your ~/.epsilon folder, and adding a load line to your einit.ecm file, see the comments in the source file. The snippets should be un-tarred into the ~/.epsilon folder. The README explains how to load them.

eg add this to your einit.ecm file:

(load-eel-from-path "ruby_mode.e" 2)
(load-eel-from-path "rubyhelp.e" 2)
(load-eel-from-path "snippets.e" 2)
(load-eel-from-path "rename_in_place.e" 2)

Also here are the color codes I use for ruby_mode, these are designed by Timothy: (Change the window-black to whatever color set you are using)

&window-black color class for ruby-brace: [0x725CEB on 0x0]
&window-black color class for ruby-class: [0xD9D240 on 0x0]
&window-black color class for ruby-comment: [0xC0C0C0 on 0x0]
&window-black color class for ruby-global: [0xFFB737 on 0x0]
&window-black color class for ruby-keyword: [0xFF8000 on 0x0]
&window-black color class for ruby-number: [0xFF9090 on 0x0]
&window-black color class for ruby-punctuation: yellow on black
&window-black color class for ruby-regexp: [0x007FFF on 0x0]
&window-black color class for ruby-shell-cmd: [0x8FFF2F on 0x0]
&window-black color class for ruby-shell-subst: [0x8FFF8F on 0x0]
&window-black color class for ruby-str-subst: [0xFFC0C8 on 0x0]
&window-black color class for ruby-string: cyan on black
&window-black color class for ruby-perl-var: red on black

Although you can browse for files that epsilon has currently open and switch between these buffers, the method is fairly crude by todays standards of tabbed windows etc, so I wrote a little graphical helper called project_browser.rb that uses the fox window toolkit. It just shows a tree of the directory it was given on the command line, and if you click on any of the files they open in the epsilon window. This is a lot like the project browser windows you find in Textmate, Eclipse and others. You need to install fox version 1.4 and the fox14 gem too to use this. It also allows you to exclude files and directories from display in the tree, by putting a YAML file called .proj_exclude.yaml in the project directory, I'll document this further if there is any interest in it (Leave a comment if you are interested). It allows multiple project directories to be open and shows them in tabs at the top. I'm also working on integrating subversion into it. It could also be adapted to work with virtually any editor that allows files to be sent to the editor by a separate process.

project browser

Posted in , ,  | Tags , , , ,  | no comments | no trackbacks

Older posts: 1 2 3