Gedittools – a plug-in for gedit.

Update September 21: The XML Highlighting algorithm has been re-implemented. Therefore, this feature is now much faster than before. Also, it is not triggered automatically. There is a new button in the toolbar to start XML highlighting.

During the past few weeks I extended gedit by several little plug-ins that I needed to have for my daily developer work. Now, I merged all those to one single configurable plug-in called gedittools.

It comes along with the following features:

  • XML highlighting: After hitting the highlighting button in the tool bar, the complete tree inside the file will be highlighted. Depending on depth different colors will be used.
  • Selection highlighting: After a double click on any word, all occurrances of the selected word will be highlighted throughout the whole current document.
  • Search selection count: After a double click on any word, all occurrances of the selected word will be counted and the sum will be displayed in the status bar of the document.
  • Launch meld to compare files: A button is added to the toolbar of gedit to allow launching meld. Therefore a screen will be displayed: It allows selection of a file which will be compared to the current active file in gedit.

The plug-in is configurable: You can choose which plug-in you want to use. To make use of the meld launcher feature, an installation of meld is required. Refer to the README file for details.

Download here

If you want to use the plug-in, feel free to download it at github: http://github.com/mmuell23/mmuell23

To install from git:

git clone http://github.com/mmuell23/mmuell23.git
cp -r mmuell23/gedittools/* ~/.gnome2/gedit/plugins

Activate plug-in in gedit preferences and configure it as you wish.

Install from zip File:

You might also download the plug-in as a zip file from github. Hit the “download source” button on the top right of the site.

Extract all files and copy to ~/.gnome2/gedit/plugins

Activate plug-in in gedit preferences and configure it as you wish.

Plug-ins for gedit: count results or compare files.

Well, after I could count words in a gedit document based on a selection I made, I decided to add another missing feature:

I needed a diff tool to compare two files that are currently opened in gedit. Unfortunately, gedit doesn’t come along with these kind of features. So, another plug-in was needed.

Meldlauncher

What it does? It simply starts the open source diff & merge tool Meld using two documents opened in gedit. That’s why I called it meldlauncher. Therefore, if you want to use meldlauncher, you will need to have Meld installed. On Ubuntu do something like this:

sudo apt-get install meld

If there are only two documents opened in gedit, meldlauncher will launch Meld and pass those two files to it. If there are more than two documents opened, meldlauncher will open a selection dialog from which you can easily choose the document to compare the current document with.

I moved both the counter plug-in and the meldlauncher plug-in to Github. Feel free to grab it from there:

http://github.com/mmuell23/mmuell23

Count search results in gedit.

Update September 21:
After all, I found some time to reimplement the algorithm for highlighting XML. It is now triggered by a new button in the toolbar. As it now does not run automatically, this will be another improvement to overall speed. Feel free to download the new version at the provided download link below or at github!

Update May 5:
Count results are now being displayed in the Status Bar instead of an alert window. Also, there were a couple of bug fixes. Feel free to download the new version at the provided download link below or at github!

Lately I was looking for a small but missing feature in gedit: I needed to be able to count all occurrances of a selected word. This is a standard feature in many other editors such as Notepad++ in the Windows world, for example. However, I didn’t come across a solution on the net, so I decided to write a little plug-in myself.

What it does: After marking a word the plug-in counts all occurrances of the selection in the current document. It adds a new button to the toolbar and an entry to the menu right in the “Search” section. On top of that you may trigger counting the selection by hitting “CTRL+SHIFT+F”. A small pop-up window will appear and show the results of the search. The results will be displayed in the status bar of the window.

How to use it: Simply mark a word, and have a look at the statusbar: The number of search results will be displayed there.

If you find it useful, feel free to download the plug-in here:

Donwload at github:
http://github.com/mmuell23/mmuell23

git clone http://github.com/mmuell23/mmuell23.git
cp -r mmuell23/gedittools/* ~/.gnome2/gedit/plugins

Ruby Hash: Convert String keys to Symbols

Ever had a hash which contained strings as keys and needed symbols instead? I do: From a REXML::Document I created a hash. Unfortunately, the keys were all strings and I needed them to be symbols at some other point in the app. Thank god, Ruby is capable of extending any object “on the fly”. So, I wrote a simple extension to Hash, which you might find useful as well:

class Hash
  #take keys of hash and transform those to a symbols
  def self.transform_keys_to_symbols(value)
    return value if not value.is_a?(Hash)
    hash = value.inject({}){|memo,(k,v)| memo[k.to_sym] = Hash.transform_keys_to_symbols(v); memo}
    return hash
  end
end

Usage is:

a = { "key" => 123, "inner_hash" => { "another_key" => "blabla" }}
Hash.transform_keys_to_symbols(a)
#returns
a = { :key => 123, :inner_hash => { :another_key => "blabla" }}

Passenger and OpenID

I recently updated Passenger 2.0.6 to 2.2.4 and experienced that openID logins were not working anymore. Seems like it tries to log output to some strange log location.

However: If anyone comes across the same problem: Simply add

OpenID::Util.logger = RAILS_DEFAULT_LOGGER

to your environment.rb file and everything will work like a treat again.

Rails’ to_xml w/ multiple associations.

This is a pain and took me about an hour to figure out today.

Rails ActiveRecord instances offer a nice function to render xml:

my_model.to_xml()

This method can be fed with a parameter

:include => []

to have all associations being integrated in the XML tree, just like when calling

my_model = MyModel.find( :include => [association])

But when I tried to use it, it always failed when dealing with nested associations. Until I found out the trick.
This is how it works: Basically you need to build a list of nested hashes.

class Book < ActiveRecord::Base
  has_many :pages
  has_one :owner
end
class Owner < ActiveRecord::Base
  has_many :books
end
class Page < ActiveRecord::Base
  has_many :spots_of_coffees
  belongs_to :book
end
class SpotOfCoffee < ActiveRecord::Base
  belongs_to :page
end

Now, you want to create a nice XML output containing a book, with its owner, pages and all spots of coffee?
Pretty easy:

  @book = Book.first
  includes = {} # let's build a hash; it's easier to read. At least for me...
  includes[:owner] = {} # owner has no association. So, let's take an empty hash as target
  includes[:pages] = { :include => :spots_of_coffee } #load pages and include its spots of coffee
    
  respond_to do |format|
    format.xml  { render :text => @book.to_xml(:include => includes) }
  end

Rails: Custom image sizes using has_attachment

Ever wanted to offer users the possibility to define their very own image sizes for uploaded pictures?

Here’s how you can quickly do that.

You will have a class acting as a an attachment such as:

class AssetImage < ActiveRecord::Base

has_attachment :content_type => :image,
:storage => :file_system,
:max_size => 1.megabytes,
:path_prefix => "public/system/images/#{ActiveRecord::Base.configurations[RAILS_ENV]['domain_name']}/assets/images",
:thumbnails => { :large => '450>', :normal => '300', :medium => '200', :thumbnail => [100,75] },
:processor => :rmagick

validates_as_attachment

...

First add a cattr_accessor to store your custom size in the class:

cattr_accessor :custom_size

Now, add a before_save callback which takes the assigned value and adds it to the list of requested image sizes. It is using the value as a minimum size while keeping aspect ratio.

#store custom size
def before_save
  return if AssetImage.custom_size.nil?
  attachment_options[:thumbnails][:custom] = AssetImage.custom_size.to_s + ">"
end

In your controller do something like this: Take a value from your parameters and store it in your model to have your image customized.

def add_image
  AssetImage.custom_size = params[:custom_size].to_i.to_s rescue "100"
  a = AssetImage.new(params[:asset_image])
  a.save
  redirect_to :action => :index
end

Nerd stuff.

Die Agentur Seibert Media hat einen kleinen Programmierer-Wettbewerb laufen:

Wer den schlankesten Code schreibt, der einen Weihnachtsbaum auf dem Bildschirm erzeugt, bekommt einen netten iPod-Schuffle.

Hier mein Beitrag, geschrieben in Ruby:

puts (0..30).map{|x|" "*(30-x)+"XX"*x+"\n"}.join+(" "*29+"||\n")*2

Und die Ausgabe auf der Konsole mit IRB:

                             XX
                            XXXX
                           XXXXXX
                          XXXXXXXX
                         XXXXXXXXXX
                        XXXXXXXXXXXX
                       XXXXXXXXXXXXXX
                      XXXXXXXXXXXXXXXX
                     XXXXXXXXXXXXXXXXXX
                    XXXXXXXXXXXXXXXXXXXX
                   XXXXXXXXXXXXXXXXXXXXXX
                  XXXXXXXXXXXXXXXXXXXXXXXX
                 XXXXXXXXXXXXXXXXXXXXXXXXXX
                XXXXXXXXXXXXXXXXXXXXXXXXXXXX
               XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
              XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
            XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
           XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
         XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
       XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
                             ||
                             ||

Use ar_mailer for future mail delivery

This little howto describes, how to use ar_mailer to schedule emails for future delivery.

Sorry for the bad formatting. Might change it someday…
1) Migrate emails table and add needed fields

  add_column :emails, :various, :string #holds classname and id of any object you want to
  add_column :emails, :type, :string #type of email
  add_column :emails, :date_to_send, :date #date to send that mail

2) Override “def find” in email.rb

  def self.find(*args)
    with_scope(:find=>{ :conditions=>["(date_to_send IS NULL OR date_to_send <= ?)", Date.today] }) do
      super(*args)
    end
  end

3) Create DelayedEmail class, inherting Email

  class DelayedEmail < Email
    before_save :set_due_date
    before_save :set_various_field
    @@days_before_sending = 21 #default is 3 weeks after creation of various object
    @@various_class = nil

    def set_due_date
      self.date_to_send = Date.today + @@days_before_sending
    end

    def set_various_field
      name = @@various_class.class.to_s + "_" rescue "NOCLASS_"
      id = @@various_class.id.to_s rescue "0"
      self.various = name + id
    end

    #tell email to which object it belongs. might be important for future deletion of unsent mails
    def self.set_various_class(c)
      @@various_class = c
    end

    #tell email how many days shall pass by before sending email
    def self.set_days(days)
      @@days_before_sending = days
    end
  end

4) Modify ar_mailer standard emailer class in controller before delivery and set it back afterwards

  DelayedEmail.set_days(10)
  DelayedEmail.set_various_class(SOMEOBJECT)
  ActionMailer::ARMailer.email_class=DelayedEmail
  #Let any mailer send an email through this class
  #eg. Mailer.deliver_mymail(...)
  ActionMailer::ARMailer.email_class=Email