QGIS at FOSS4G 2011 in Denver
Sourcepole is conducting a QGIS workshop and giving two presentations:
- Workshop: New features for QGIS power users
- QGIS, what’s new?
- Publishing maps from the desktop with QGIS server
There are more QGIS workshops and presentations:
- Workshop: Customizing QGIS with Python Plugins
- Efficiently using PostGIS with QGIS
- Quantum GIS & Inkscape: Cartographic Tools for Attractive Maps
- Web Mapping Performance Shootout
Case studies:
- QGIS in an Academic Library: A Case Study
- Cellular Automata QuantumGIS plugin and web-based application
- A WPS Based Biogeography Tool for QGIS
- FOSS4G: Technology Enabling Humanitarian Relief Efforts
- A Prototype of open source tool for water resources management in developing countries
So if you’re interested in QGIS, don’t miss FOSS4G 2011 in Denver. Early-bird registration ends June 30th.
QGIS at FOSS4G 2011 in Denver
Sourcepole is conducting a QGIS workshop and giving two presentations:
- Workshop: New features for QGIS power users
- QGIS, what’s new?
- Publishing maps from the desktop with QGIS server
There are more QGIS workshops and presentations:
- Workshop: Customizing QGIS with Python Plugins
- Efficiently using PostGIS with QGIS
- Quantum GIS & Inkscape: Cartographic Tools for Attractive Maps
- Web Mapping Performance Shootout
Case studies:
- QGIS in an Academic Library: A Case Study
- Cellular Automata QuantumGIS plugin and web-based application
- A WPS Based Biogeography Tool for QGIS
- FOSS4G: Technology Enabling Humanitarian Relief Efforts
- A Prototype of open source tool for water resources management in developing countries
So if you’re interested in QGIS, don’t miss FOSS4G 2011 in Denver. Early-bird registration ends June 30th.
QGIS at FOSS4G 2011 in Denver
Sourcepole is conducting a QGIS workshop and giving two presentations:
- Workshop: New features for QGIS power users
- QGIS, what’s new?
- Publishing maps from the desktop with QGIS server
There are more QGIS workshops and presentations:
- Workshop: Customizing QGIS with Python Plugins
- Efficiently using PostGIS with QGIS
- Quantum GIS & Inkscape: Cartographic Tools for Attractive Maps
- Web Mapping Performance Shootout
Case studies:
- QGIS in an Academic Library: A Case Study
- Cellular Automata QuantumGIS plugin and web-based application
- A WPS Based Biogeography Tool for QGIS
- FOSS4G: Technology Enabling Humanitarian Relief Efforts
- A Prototype of open source tool for water resources management in developing countries
So if you’re interested in QGIS, don’t miss FOSS4G 2011 in Denver. Early-bird registration ends June 30th.
QGIS at FOSS4G 2011 in Denver
Sourcepole is conducting a QGIS workshop and giving two presentations:
- Workshop: New features for QGIS power users
- QGIS, what’s new?
- Publishing maps from the desktop with QGIS server
There are more QGIS workshops and presentations:
- Workshop: Customizing QGIS with Python Plugins
- Efficiently using PostGIS with QGIS
- Quantum GIS & Inkscape: Cartographic Tools for Attractive Maps
- Web Mapping Performance Shootout
Case studies:
- QGIS in an Academic Library: A Case Study
- Cellular Automata QuantumGIS plugin and web-based application
- A WPS Based Biogeography Tool for QGIS
- FOSS4G: Technology Enabling Humanitarian Relief Efforts
- A Prototype of open source tool for water resources management in developing countries
So if you’re interested in QGIS, don’t miss FOSS4G 2011 in Denver. Early-bird registration ends June 30th.
Reducing magic in Ruby's Forwardable class implementation
Abstract
Using string-eval in Ruby for metaprogramming is unnecessarily obscuring. Ruby’s more modern
and specific metaprogramming methods should be used instead whenever possible. This problem
is illustrated on the example of Ruby’s Forwardable
class.
In detail…
Ruby’s Forwardable class is using metaprogramming to forward calls from a frontend interface to an instance in the back executing the call.
Metaprogramming is the discipline of making code that creates code. This task allready is rather abstract and hard to grasp in itself. Having hard to grasp code is a liability. One of the goals of writing code is allways to keep the code as simple and as well understandable as possible.
Additionaly, metaprogramming code itself is difficult to read and understand: that is because the metaprogramming code will not necessarily express what the code it is creating is about, but only how it is creating that code. As such the code it is creating can be invisible to you as a reader of the source code - the created code will only start to exist at runtime.
One would therefore expect that programmers would try especially hard when they metaprogram to make that particular kind of code expressive and easy to understand.
Another consequence of the fact that the code produced by metaprogramming is not necessarily visible, is that debugging becomes more difficult: when analyzing problems you’ll not only be unsure how the programm works, but in addition, you won’t even be sure how the code that is executed looks like - since it is only generated at runtime.
This post is focusing on the last problem: debugging of metaprogrammed code.
There are two approaches to metaprogramming. One is to have as far as possible compile-time parseable code and the other is to let the code only be parsed at runtime.
As of version 1.9.2, Ruby’s Forwardable
class is using the
latter. The metaprogramming code in Ruby 1.8.7 looks like this:
module_eval(<
As said, this has the consequence of the metaprogrammed code being completely invisible to the parser and other tools such as editors and debuggers.
This results in the following:
$ cat queue.rb require 'rubygems' require 'forwardable' require 'ruby-debug' class Queue extend Forwardable def initialize @q = [ ] # prepare delegate object end # setup preferred interface, enq() and deq()... def_delegator :@q, :push, :enq def_delegator :@q, :shift, :deq # support some general Array methods that fit Queues well def_delegators :@q, :clear, :first, :push, :shift, :size end q = Queue.new debugger # ------ DEBUGGING FROM HERE ON ----- q.enq 1, 2, 3, 4, 5 q.push 6 q.shift # => 1 while q.size > 0 puts q.deq end q.enq "Ruby", "Perl", "Python" puts q.first q.clear puts q.first
$ ruby queue.rb queue.rb:24 q.enq 1, 2, 3, 4, 5 (rdb:1) step (__FORWARDABLE__):2 (rdb:1) list = *** No sourcefile available for (__FORWARDABLE__) (rdb:1) step (__FORWARDABLE__):3
In other words, you are rather lost allready - otherwise you probably wouldn’t be stepping through your code - and in that situation it happens that your debugger gets completely lost as well, since it does not know any more where in the code it is and what it exactly is executing.
That’s nothing the programmer wishes for. In a situation where you are debugging you want to have a maximally clear view of all state, including what code you are currently executing.
Chaning that situation requires making as much of the metaprogrammed code visible to the parser, which is the second approach to metaprogramming mentioned previously:
$ cat forwardable2.rb ... self.send(:define_method, ali) do |*args,█| begin instance_variable_get(accessor).__send__(method, *args,█) rescue Exception [email protected]_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable2::debug Kernel::raise end end
Note that it’s the same code as before, except that we do not do eval("string")
any more,
but instead are using specific, more modern metaprogramming tools provided by standard Ruby.
The result is the following:
$ ruby queue.rb queue.rb:22 q.enq 1, 2, 3, 4, 5 (rdb:1) step /usr/lib/ruby/1.8/forwardable2.rb:149 begin (rdb:1) list = [144, 153] in /usr/lib/ruby/1.8/forwardable2.rb 144 accessor = accessor.id2name if accessor.kind_of?(Integer) 145 method = method.id2name if method.kind_of?(Integer) 146 ali = ali.id2name if ali.kind_of?(Integer) 147 148 self.send(:define_method, ali) do |*args,█| => 149 begin 150 instance_variable_get(accessor).__send__(method, *args,█) 151 rescue Exception 152 [email protected]_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable2::debug 153 Kernel::raise (rdb:1) step /usr/lib/ruby/1.8/forwardable2.rb:150 instance_variable_get(accessor).__send__(method, *args,█)
Allready much, much better.
Of course, with the string-eval approach to metaprogramming Ruby itself could do better by saving the string that is being evaled to be able to refer to it later at step-through time. However currently we don’t have this option.
Tomáš Pospíšek
Reducing magic in Ruby's Forwardable class implementation
Abstract
Using string-eval in Ruby for metaprogramming is unnecessarily obscuring. Ruby’s more modern
and specific metaprogramming methods should be used instead whenever possible. This problem
is illustrated on the example of Ruby’s Forwardable
class.
In detail…
Ruby’s Forwardable class is using metaprogramming to forward calls from a frontend interface to an instance in the back executing the call.
Metaprogramming is the discipline of making code that creates code. This task allready is rather abstract and hard to grasp in itself. Having hard to grasp code is a liability. One of the goals of writing code is allways to keep the code as simple and as well understandable as possible.
Additionaly, metaprogramming code itself is difficult to read and understand: that is because the metaprogramming code will not necessarily express what the code it is creating is about, but only how it is creating that code. As such the code it is creating can be invisible to you as a reader of the source code - the created code will only start to exist at runtime.
One would therefore expect that programmers would try especially hard when they metaprogram to make that particular kind of code expressive and easy to understand.
Another consequence of the fact that the code produced by metaprogramming is not necessarily visible, is that debugging becomes more difficult: when analyzing problems you’ll not only be unsure how the programm works, but in addition, you won’t even be sure how the code that is executed looks like - since it is only generated at runtime.
This post is focusing on the last problem: debugging of metaprogrammed code.
There are two approaches to metaprogramming. One is to have as far as possible compile-time parseable code and the other is to let the code only be parsed at runtime.
As of version 1.9.2, Ruby’s Forwardable
class is using the
latter. The metaprogramming code in Ruby 1.8.7 looks like this:
module_eval(<
As said, this has the consequence of the metaprogrammed code being completely invisible to the parser and other tools such as editors and debuggers.
This results in the following:
$ cat queue.rb require 'rubygems' require 'forwardable' require 'ruby-debug' class Queue extend Forwardable def initialize @q = [ ] # prepare delegate object end # setup preferred interface, enq() and deq()... def_delegator :@q, :push, :enq def_delegator :@q, :shift, :deq # support some general Array methods that fit Queues well def_delegators :@q, :clear, :first, :push, :shift, :size end q = Queue.new debugger # ------ DEBUGGING FROM HERE ON ----- q.enq 1, 2, 3, 4, 5 q.push 6 q.shift # => 1 while q.size > 0 puts q.deq end q.enq "Ruby", "Perl", "Python" puts q.first q.clear puts q.first
$ ruby queue.rb queue.rb:24 q.enq 1, 2, 3, 4, 5 (rdb:1) step (__FORWARDABLE__):2 (rdb:1) list = *** No sourcefile available for (__FORWARDABLE__) (rdb:1) step (__FORWARDABLE__):3
In other words, you are rather lost allready - otherwise you probably wouldn’t be stepping through your code - and in that situation it happens that your debugger gets completely lost as well, since it does not know any more where in the code it is and what it exactly is executing.
That’s nothing the programmer wishes for. In a situation where you are debugging you want to have a maximally clear view of all state, including what code you are currently executing.
Chaning that situation requires making as much of the metaprogrammed code visible to the parser, which is the second approach to metaprogramming mentioned previously:
$ cat forwardable2.rb ... self.send(:define_method, ali) do |*args,█| begin instance_variable_get(accessor).__send__(method, *args,█) rescue Exception [email protected]_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable2::debug Kernel::raise end end
Note that it’s the same code as before, except that we do not do eval("string")
any more,
but instead are using specific, more modern metaprogramming tools provided by standard Ruby.
The result is the following:
$ ruby queue.rb queue.rb:22 q.enq 1, 2, 3, 4, 5 (rdb:1) step /usr/lib/ruby/1.8/forwardable2.rb:149 begin (rdb:1) list = [144, 153] in /usr/lib/ruby/1.8/forwardable2.rb 144 accessor = accessor.id2name if accessor.kind_of?(Integer) 145 method = method.id2name if method.kind_of?(Integer) 146 ali = ali.id2name if ali.kind_of?(Integer) 147 148 self.send(:define_method, ali) do |*args,█| => 149 begin 150 instance_variable_get(accessor).__send__(method, *args,█) 151 rescue Exception 152 [email protected]_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable2::debug 153 Kernel::raise (rdb:1) step /usr/lib/ruby/1.8/forwardable2.rb:150 instance_variable_get(accessor).__send__(method, *args,█)
Allready much, much better.
Of course, with the string-eval approach to metaprogramming Ruby itself could do better by saving the string that is being evaled to be able to refer to it later at step-through time. However currently we don’t have this option.
Tomáš Pospíšek
Reducing magic in Ruby's Forwardable class implementation
Abstract
Using string-eval in Ruby for metaprogramming is unnecessarily obscuring. Ruby’s more modern
and specific metaprogramming methods should be used instead whenever possible. This problem
is illustrated on the example of Ruby’s Forwardable
class.
In detail…
Ruby’s Forwardable class is using metaprogramming to forward calls from a frontend interface to an instance in the back executing the call.
Metaprogramming is the discipline of making code that creates code. This task allready is rather abstract and hard to grasp in itself. Having hard to grasp code is a liability. One of the goals of writing code is allways to keep the code as simple and as well understandable as possible.
Additionaly, metaprogramming code itself is difficult to read and understand: that is because the metaprogramming code will not necessarily express what the code it is creating is about, but only how it is creating that code. As such the code it is creating can be invisible to you as a reader of the source code - the created code will only start to exist at runtime.
One would therefore expect that programmers would try especially hard when they metaprogram to make that particular kind of code expressive and easy to understand.
Another consequence of the fact that the code produced by metaprogramming is not necessarily visible, is that debugging becomes more difficult: when analyzing problems you’ll not only be unsure how the programm works, but in addition, you won’t even be sure how the code that is executed looks like - since it is only generated at runtime.
This post is focusing on the last problem: debugging of metaprogrammed code.
There are two approaches to metaprogramming. One is to have as far as possible compile-time parseable code and the other is to let the code only be parsed at runtime.
As of version 1.9.2, Ruby’s Forwardable
class is using the
latter. The metaprogramming code in Ruby 1.8.7 looks like this:
module_eval(<
As said, this has the consequence of the metaprogrammed code being completely invisible to the parser and other tools such as editors and debuggers.
This results in the following:
$ cat queue.rb require 'rubygems' require 'forwardable' require 'ruby-debug' class Queue extend Forwardable def initialize @q = [ ] # prepare delegate object end # setup preferred interface, enq() and deq()... def_delegator :@q, :push, :enq def_delegator :@q, :shift, :deq # support some general Array methods that fit Queues well def_delegators :@q, :clear, :first, :push, :shift, :size end q = Queue.new debugger # ------ DEBUGGING FROM HERE ON ----- q.enq 1, 2, 3, 4, 5 q.push 6 q.shift # => 1 while q.size > 0 puts q.deq end q.enq "Ruby", "Perl", "Python" puts q.first q.clear puts q.first
$ ruby queue.rb queue.rb:24 q.enq 1, 2, 3, 4, 5 (rdb:1) step (__FORWARDABLE__):2 (rdb:1) list = *** No sourcefile available for (__FORWARDABLE__) (rdb:1) step (__FORWARDABLE__):3
In other words, you are rather lost allready - otherwise you probably wouldn’t be stepping through your code - and in that situation it happens that your debugger gets completely lost as well, since it does not know any more where in the code it is and what it exactly is executing.
That’s nothing the programmer wishes for. In a situation where you are debugging you want to have a maximally clear view of all state, including what code you are currently executing.
Chaning that situation requires making as much of the metaprogrammed code visible to the parser, which is the second approach to metaprogramming mentioned previously:
$ cat forwardable2.rb ... self.send(:define_method, ali) do |*args,█| begin instance_variable_get(accessor).__send__(method, *args,█) rescue Exception [email protected]_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable2::debug Kernel::raise end end
Note that it’s the same code as before, except that we do not do eval("string")
any more,
but instead are using specific, more modern metaprogramming tools provided by standard Ruby.
The result is the following:
$ ruby queue.rb queue.rb:22 q.enq 1, 2, 3, 4, 5 (rdb:1) step /usr/lib/ruby/1.8/forwardable2.rb:149 begin (rdb:1) list = [144, 153] in /usr/lib/ruby/1.8/forwardable2.rb 144 accessor = accessor.id2name if accessor.kind_of?(Integer) 145 method = method.id2name if method.kind_of?(Integer) 146 ali = ali.id2name if ali.kind_of?(Integer) 147 148 self.send(:define_method, ali) do |*args,█| => 149 begin 150 instance_variable_get(accessor).__send__(method, *args,█) 151 rescue Exception 152 [email protected]_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable2::debug 153 Kernel::raise (rdb:1) step /usr/lib/ruby/1.8/forwardable2.rb:150 instance_variable_get(accessor).__send__(method, *args,█)
Allready much, much better.
Of course, with the string-eval approach to metaprogramming Ruby itself could do better by saving the string that is being evaled to be able to refer to it later at step-through time. However currently we don’t have this option.
Tomáš Pospíšek
Reducing magic in Ruby's Forwardable class implementation
Abstract
Using string-eval in Ruby for metaprogramming is unnecessarily obscuring. Ruby’s more modern
and specific metaprogramming methods should be used instead whenever possible. This problem
is illustrated on the example of Ruby’s Forwardable
class.
In detail…
Ruby’s Forwardable class is using metaprogramming to forward calls from a frontend interface to an instance in the back executing the call.
Metaprogramming is the discipline of making code that creates code. This task allready is rather abstract and hard to grasp in itself. Having hard to grasp code is a liability. One of the goals of writing code is allways to keep the code as simple and as well understandable as possible.
Additionaly, metaprogramming code itself is difficult to read and understand: that is because the metaprogramming code will not necessarily express what the code it is creating is about, but only how it is creating that code. As such the code it is creating can be invisible to you as a reader of the source code - the created code will only start to exist at runtime.
One would therefore expect that programmers would try especially hard when they metaprogram to make that particular kind of code expressive and easy to understand.
Another consequence of the fact that the code produced by metaprogramming is not necessarily visible, is that debugging becomes more difficult: when analyzing problems you’ll not only be unsure how the programm works, but in addition, you won’t even be sure how the code that is executed looks like - since it is only generated at runtime.
This post is focusing on the last problem: debugging of metaprogrammed code.
There are two approaches to metaprogramming. One is to have as far as possible compile-time parseable code and the other is to let the code only be parsed at runtime.
As of version 1.9.2, Ruby’s Forwardable
class is using the
latter. The metaprogramming code in Ruby 1.8.7 looks like this:
module_eval(<
As said, this has the consequence of the metaprogrammed code being completely invisible to the parser and other tools such as editors and debuggers.
This results in the following:
$ cat queue.rb require 'rubygems' require 'forwardable' require 'ruby-debug' class Queue extend Forwardable def initialize @q = [ ] # prepare delegate object end # setup preferred interface, enq() and deq()... def_delegator :@q, :push, :enq def_delegator :@q, :shift, :deq # support some general Array methods that fit Queues well def_delegators :@q, :clear, :first, :push, :shift, :size end q = Queue.new debugger # ------ DEBUGGING FROM HERE ON ----- q.enq 1, 2, 3, 4, 5 q.push 6 q.shift # => 1 while q.size > 0 puts q.deq end q.enq "Ruby", "Perl", "Python" puts q.first q.clear puts q.first
$ ruby queue.rb queue.rb:24 q.enq 1, 2, 3, 4, 5 (rdb:1) step (__FORWARDABLE__):2 (rdb:1) list = *** No sourcefile available for (__FORWARDABLE__) (rdb:1) step (__FORWARDABLE__):3
In other words, you are rather lost allready - otherwise you probably wouldn’t be stepping through your code - and in that situation it happens that your debugger gets completely lost as well, since it does not know any more where in the code it is and what it exactly is executing.
That’s nothing the programmer wishes for. In a situation where you are debugging you want to have a maximally clear view of all state, including what code you are currently executing.
Chaning that situation requires making as much of the metaprogrammed code visible to the parser, which is the second approach to metaprogramming mentioned previously:
$ cat forwardable2.rb ... self.send(:define_method, ali) do |*args,█| begin instance_variable_get(accessor).__send__(method, *args,█) rescue Exception [email protected]_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable2::debug Kernel::raise end end
Note that it’s the same code as before, except that we do not do eval("string")
any more,
but instead are using specific, more modern metaprogramming tools provided by standard Ruby.
The result is the following:
$ ruby queue.rb queue.rb:22 q.enq 1, 2, 3, 4, 5 (rdb:1) step /usr/lib/ruby/1.8/forwardable2.rb:149 begin (rdb:1) list = [144, 153] in /usr/lib/ruby/1.8/forwardable2.rb 144 accessor = accessor.id2name if accessor.kind_of?(Integer) 145 method = method.id2name if method.kind_of?(Integer) 146 ali = ali.id2name if ali.kind_of?(Integer) 147 148 self.send(:define_method, ali) do |*args,█| => 149 begin 150 instance_variable_get(accessor).__send__(method, *args,█) 151 rescue Exception 152 [email protected]_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable2::debug 153 Kernel::raise (rdb:1) step /usr/lib/ruby/1.8/forwardable2.rb:150 instance_variable_get(accessor).__send__(method, *args,█)
Allready much, much better.
Of course, with the string-eval approach to metaprogramming Ruby itself could do better by saving the string that is being evaled to be able to refer to it later at step-through time. However currently we don’t have this option.
Tomáš Pospíšek
QGIS Mobile GSoC has started
Yesterday, we had our first meeting with Marco Bernasocchi, who just started his Google Summer of Code project. The project goals are:
- porting QGIS to the Android platform
- adapt the QGIS GUI for tablet computers
- write a driver for the built-in GPS
- create a QGIS “mini” application for mobile phones
Marco Hugentobler is mentoring the project and updated information will be available on a QGIS Wiki page. We wish Marco good luck and are looking forward to a portable QGIS this year!
QGIS Mobile GSoC has started
Yesterday, we had our first meeting with Marco Bernasocchi, who just started his Google Summer of Code project. The project goals are:
- porting QGIS to the Android platform
- adapt the QGIS GUI for tablet computers
- write a driver for the built-in GPS
- create a QGIS “mini” application for mobile phones
Marco Hugentobler is mentoring the project and updated information will be available on a QGIS Wiki page. We wish Marco good luck and are looking forward to a portable QGIS this year!
QGIS Mobile GSoC has started
Yesterday, we had our first meeting with Marco Bernasocchi, who just started his Google Summer of Code project. The project goals are:
- porting QGIS to the Android platform
- adapt the QGIS GUI for tablet computers
- write a driver for the built-in GPS
- create a QGIS “mini” application for mobile phones
Marco Hugentobler is mentoring the project and updated information will be available on a QGIS Wiki page. We wish Marco good luck and are looking forward to a portable QGIS this year!
QGIS Mobile GSoC has started
Yesterday, we had our first meeting with Marco Bernasocchi, who just started his Google Summer of Code project. The project goals are:
- porting QGIS to the Android platform
- adapt the QGIS GUI for tablet computers
- write a driver for the built-in GPS
- create a QGIS “mini” application for mobile phones
Marco Hugentobler is mentoring the project and updated information will be available on a QGIS Wiki page. We wish Marco good luck and are looking forward to a portable QGIS this year!
extending RedCloth markup
There are various approaches when trying to extend the Textile markup that RedCloth understands with own tags or syntax. Some approaches documented on the net have changed or don’t work any more, since RedCloth has been rewritten in Version 4.
Below is a fairly robust aproach, that is based on the assumption, that RedCloth leaves HTML tags inside the markup untouched and passes them on to the application consuming the translated markup.
The below code has been used in the Madek project. Madek, a Ruby On Rails application, uses irwi which provides a Wiki to Madek. And finally irwi uses RedCloth to do the rendering from Textile to HTML. That’s where we hook in.
We want to have a few special tags, which make the life of the Madek Wiki admin simpler, by letting him write the following inside the Textile markup:
[media=210 | Das Huhn]
[screenshot=210 | Das Huhn]
[video=210 | Das Huhn]
That will finally produce this HTML output:
<a href="/media_entries/210">Das Huhn</a>
<img src="/media_entries/210/image" title="Das Huhn"/>
<video src="/media_entries/210/image" title="Das Huhn"/>
<a href='/media_entries/210'>(see video)</a>
</video>
Here’s the implementation:
class RedClothMadek
ActionView::Base.sanitized_allowed_tags << 'video'
def initialize
require 'redcloth'
end
def format( text )
::RedCloth.new( replace_madek_tags(text) ).to_html
end
# Transforms the follwing Textile markups:
#
# [media=210 | Das Huhn] -> <a href="/media_entries/210">Das Huhn</a>
# [screenshot=210 | Das Huhn] -> <img src="/media_entries/210/image" title="Das Huhn"/>
# [video=210 | Das Huhn] -> <video src="/media_entries/210/image" title="Das Huhn"/>
# <a href='/media_entries/210'>(see video)</a>
# </video>
#
def replace_madek_tags( text )
# unfortunately having multiple matches in gsub doesn't seem to work, therefore
# we fall back to $1 $2
#
text.gsub(/[\s*media\s*=\s*(\d+)\s*\|\s*([^]]+)\s*]/) { |number,txt|
"<a href='/media_entries/#{$1}'>#{h($2)}</a>" }.
gsub(/[\s*screenshot\s*=\s*(\d+)\s*\|\s*([^]]+)\s*]/) { |number,title|
"<img src='/media_entries/#{$1}/image' title='#{h($2)}'/>" }.
gsub(/[\s*video\s*=\s*(\d+)\s*\|\s*([^]]+)\s*]/) { |number,title|
"<video src='/media_entries/#{$1}/image' title='#{h($2)}'>" +
"<a href='/media_entries/#{$1}'>(see Wideo)</a>" +
"</video>" }
end
end
And finally, irwi needs to be told to use that formatter instead of RedCloth directly. From config/environment.rb
:
require "#{Rails.root}/lib/red_cloth_madek.rb"
Irwi.config.formatter = RedClothMadek.new
Tomáš Pospíšek
extending RedCloth markup
There are various approaches when trying to extend the Textile markup that RedCloth understands with own tags or syntax. Some approaches documented on the net have changed or don’t work any more, since RedCloth has been rewritten in Version 4.
Below is a fairly robust aproach, that is based on the assumption, that RedCloth leaves HTML tags inside the markup untouched and passes them on to the application consuming the translated markup.
The below code has been used in the Madek project. Madek, a Ruby On Rails application, uses irwi which provides a Wiki to Madek. And finally irwi uses RedCloth to do the rendering from Textile to HTML. That’s where we hook in.
We want to have a few special tags, which make the life of the Madek Wiki admin simpler, by letting him write the following inside the Textile markup:
[media=210 | Das Huhn]
[screenshot=210 | Das Huhn]
[video=210 | Das Huhn]
That will finally produce this HTML output:
<a href="/media_entries/210">Das Huhn</a>
<img src="/media_entries/210/image" title="Das Huhn"/>
<video src="/media_entries/210/image" title="Das Huhn"/>
<a href='/media_entries/210'>(see video)</a>
</video>
Here’s the implementation:
class RedClothMadek
ActionView::Base.sanitized_allowed_tags << 'video'
def initialize
require 'redcloth'
end
def format( text )
::RedCloth.new( replace_madek_tags(text) ).to_html
end
# Transforms the follwing Textile markups:
#
# [media=210 | Das Huhn] -> <a href="/media_entries/210">Das Huhn</a>
# [screenshot=210 | Das Huhn] -> <img src="/media_entries/210/image" title="Das Huhn"/>
# [video=210 | Das Huhn] -> <video src="/media_entries/210/image" title="Das Huhn"/>
# <a href='/media_entries/210'>(see video)</a>
# </video>
#
def replace_madek_tags( text )
# unfortunately having multiple matches in gsub doesn't seem to work, therefore
# we fall back to $1 $2
#
text.gsub(/[\s*media\s*=\s*(\d+)\s*\|\s*([^]]+)\s*]/) { |number,txt|
"<a href='/media_entries/#{$1}'>#{h($2)}</a>" }.
gsub(/[\s*screenshot\s*=\s*(\d+)\s*\|\s*([^]]+)\s*]/) { |number,title|
"<img src='/media_entries/#{$1}/image' title='#{h($2)}'/>" }.
gsub(/[\s*video\s*=\s*(\d+)\s*\|\s*([^]]+)\s*]/) { |number,title|
"<video src='/media_entries/#{$1}/image' title='#{h($2)}'>" +
"<a href='/media_entries/#{$1}'>(see Wideo)</a>" +
"</video>" }
end
end
And finally, irwi needs to be told to use that formatter instead of RedCloth directly. From config/environment.rb
:
require "#{Rails.root}/lib/red_cloth_madek.rb"
Irwi.config.formatter = RedClothMadek.new
Tomáš Pospíšek
extending RedCloth markup
There are various approaches when trying to extend the Textile markup that RedCloth understands with own tags or syntax. Some approaches documented on the net have changed or don’t work any more, since RedCloth has been rewritten in Version 4.
Below is a fairly robust aproach, that is based on the assumption, that RedCloth leaves HTML tags inside the markup untouched and passes them on to the application consuming the translated markup.
The below code has been used in the Madek project. Madek, a Ruby On Rails application, uses irwi which provides a Wiki to Madek. And finally irwi uses RedCloth to do the rendering from Textile to HTML. That’s where we hook in.
We want to have a few special tags, which make the life of the Madek Wiki admin simpler, by letting him write the following inside the Textile markup:
[media=210 | Das Huhn]
[screenshot=210 | Das Huhn]
[video=210 | Das Huhn]
That will finally produce this HTML output:
<a href="/media_entries/210">Das Huhn</a>
<img src="/media_entries/210/image" title="Das Huhn"/>
<video src="/media_entries/210/image" title="Das Huhn"/>
<a href='/media_entries/210'>(see video)</a>
</video>
Here’s the implementation:
class RedClothMadek
ActionView::Base.sanitized_allowed_tags << 'video'
def initialize
require 'redcloth'
end
def format( text )
::RedCloth.new( replace_madek_tags(text) ).to_html
end
# Transforms the follwing Textile markups:
#
# [media=210 | Das Huhn] -> <a href="/media_entries/210">Das Huhn</a>
# [screenshot=210 | Das Huhn] -> <img src="/media_entries/210/image" title="Das Huhn"/>
# [video=210 | Das Huhn] -> <video src="/media_entries/210/image" title="Das Huhn"/>
# <a href='/media_entries/210'>(see video)</a>
# </video>
#
def replace_madek_tags( text )
# unfortunately having multiple matches in gsub doesn't seem to work, therefore
# we fall back to $1 $2
#
text.gsub(/[\s*media\s*=\s*(\d+)\s*\|\s*([^]]+)\s*]/) { |number,txt|
"<a href='/media_entries/#{$1}'>#{h($2)}</a>" }.
gsub(/[\s*screenshot\s*=\s*(\d+)\s*\|\s*([^]]+)\s*]/) { |number,title|
"<img src='/media_entries/#{$1}/image' title='#{h($2)}'/>" }.
gsub(/[\s*video\s*=\s*(\d+)\s*\|\s*([^]]+)\s*]/) { |number,title|
"<video src='/media_entries/#{$1}/image' title='#{h($2)}'>" +
"<a href='/media_entries/#{$1}'>(see Wideo)</a>" +
"</video>" }
end
end
And finally, irwi needs to be told to use that formatter instead of RedCloth directly. From config/environment.rb
:
require "#{Rails.root}/lib/red_cloth_madek.rb"
Irwi.config.formatter = RedClothMadek.new
Tomáš Pospíšek
annotating third party web pages
Problem: I have a web site/page that I visit regularily which I want to annotate with my notes.
More specifically, I was regularly searching through the Homegate real estate hub looking for a new home. It goes without saying that I was again and again forgetting which objects I had already looked at, which objects were really interesting and I should check out more closely.
Therefore the need to annotate search results.
The here presented approach should be applicable for annotation of other web pages as well. It’s based on the observation, that restful web applications need to operate with asset IDs. These asset IDs can be reused to enrich the asset locally with additional data, such as notes. Thus we’re looking for those IDs in specific elements of the page and add a bit of HTML markup to those places.
Of course that aproach only works as long as the web site doesn’t heavily change its markup and doesn’t rendomly change asset IDs.
Here’s a screenshot of regular Homegate search results:
And here’s the same page after scripting it with Greasemonkey:
You’ll notice the input field with the comment in it.
The idea is simple: add an input box to each search result, where you write your comment. When the focus leaves the input box, the comment is stored to localStorage.
Starting with Greasemonkey is quite easy. There are howtos and templates to start from, such as this one.
However, regular JavaScripting and Greasemonkey JavaScripting do not work in exactly the same way:
One of the differences is that Greasemonkey creates a separate JavaScript environment, in which the Greasemonkey scripts are executed. That is calling Javascript contained in the page from Greasemonkey and the inverse calling Greasemonkey scripts from the page is not possible by default. This is on purpose, so that the web page can not detect and not interfere with the Greasemonkey scripts, because you want your Greasemonkey scripts to work allways on some page, whether or not that page likes it or not. Therefore no interference is possible.
Greasemonkey however provides a standard way to access the web page’s scripts, and that’s through the “unsafeWindow” object, which is a reference to the web page’s environment.
I had two mechanisms I had to make accessible using the “unsafeWindow” handle:
- the first was accessing JQuery, which is included by default by the Homegate page. Since I needed to use JQuery functions in my Greasemonkey script, I got a reference to it via the standard Greasemonkey precedure:
var jQuery = unsafeWindow['jQuery'];
- the second mechanism that needed to cross the boundaries between the web page and Greasemonkey was callbacks from the web page to my Greasemonkey script. This is necessary, because I’m attaching “input” elements to each search result, which contain a note and which, “onblur”, need to call a function that saves the content of the input box. Here’s part that constructs the input element:
jQuery("<input onclick='event.cancelBubble = true;'" + " onblur='saveComment(this, immoID);'>").insertAfter(immoElement);
And this is the function that gets called back by “onblur”:
unsafeWindow.saveComment = function(element, immoID) { unsafeWindow.localStorage.setItem(immoID, element.value); };
The next interesting thing you’ll note is usage of ‘locaStorage’. Support for the latter in browsers does not seem mature yet. One problem I’ve encountered when developing under Firefox 3.6 was that saving to ‘localStorage’ was not possible when cookies were disabled (see this report). Thus you’ll need to permanently enable cookies for Homegate in order for the script to be able to save its data.
Finally, while developing, a major problem was, that Firefox did not show me errors in the Greasemonkey scripts. Thus either the script would work or not work and fail completely silently. That made debugging a bit painful.
So now, here’s the script.
Tomáš Pospíšek
PS: This script also lives at userscripts.org
annotating third party web pages
Problem: I have a web site/page that I visit regularily which I want to annotate with my notes.
More specifically, I was regularly searching through the Homegate real estate hub looking for a new home. It goes without saying that I was again and again forgetting which objects I had already looked at, which objects were really interesting and I should check out more closely.
Therefore the need to annotate search results.
The here presented approach should be applicable for annotation of other web pages as well. It’s based on the observation, that restful web applications need to operate with asset IDs. These asset IDs can be reused to enrich the asset locally with additional data, such as notes. Thus we’re looking for those IDs in specific elements of the page and add a bit of HTML markup to those places.
Of course that aproach only works as long as the web site doesn’t heavily change its markup and doesn’t rendomly change asset IDs.
Here’s a screenshot of regular Homegate search results:
And here’s the same page after scripting it with Greasemonkey:
You’ll notice the input field with the comment in it.
The idea is simple: add an input box to each search result, where you write your comment. When the focus leaves the input box, the comment is stored to localStorage.
Starting with Greasemonkey is quite easy. There are howtos and templates to start from, such as this one.
However, regular JavaScripting and Greasemonkey JavaScripting do not work in exactly the same way:
One of the differences is that Greasemonkey creates a separate JavaScript environment, in which the Greasemonkey scripts are executed. That is calling Javascript contained in the page from Greasemonkey and the inverse calling Greasemonkey scripts from the page is not possible by default. This is on purpose, so that the web page can not detect and not interfere with the Greasemonkey scripts, because you want your Greasemonkey scripts to work allways on some page, whether or not that page likes it or not. Therefore no interference is possible.
Greasemonkey however provides a standard way to access the web page’s scripts, and that’s through the “unsafeWindow” object, which is a reference to the web page’s environment.
I had two mechanisms I had to make accessible using the “unsafeWindow” handle:
- the first was accessing JQuery, which is included by default by the Homegate page. Since I needed to use JQuery functions in my Greasemonkey script, I got a reference to it via the standard Greasemonkey precedure:
var jQuery = unsafeWindow['jQuery'];
- the second mechanism that needed to cross the boundaries between the web page and Greasemonkey was callbacks from the web page to my Greasemonkey script. This is necessary, because I’m attaching “input” elements to each search result, which contain a note and which, “onblur”, need to call a function that saves the content of the input box. Here’s part that constructs the input element:
jQuery("<input onclick='event.cancelBubble = true;'" + " onblur='saveComment(this, immoID);'>").insertAfter(immoElement);
And this is the function that gets called back by “onblur”:
unsafeWindow.saveComment = function(element, immoID) { unsafeWindow.localStorage.setItem(immoID, element.value); };
The next interesting thing you’ll note is usage of ‘locaStorage’. Support for the latter in browsers does not seem mature yet. One problem I’ve encountered when developing under Firefox 3.6 was that saving to ‘localStorage’ was not possible when cookies were disabled (see this report). Thus you’ll need to permanently enable cookies for Homegate in order for the script to be able to save its data.
Finally, while developing, a major problem was, that Firefox did not show me errors in the Greasemonkey scripts. Thus either the script would work or not work and fail completely silently. That made debugging a bit painful.
So now, here’s the script.
Tomáš Pospíšek
PS: This script also lives at userscripts.org