Tonight I ended up giving an impromptu overview of Argible at the monthly Chicago Area Ruby Group. Utilizing annotations in Ruby code seemed foreign to several of the folks there. So, I quickly went over the Argible source code to illustrate how annotations can be implemented in Ruby (via the Module#method_added(name) callback). This code alone seemed to interest several of the people there.
Additionally, I tried to stress that the concept of using an argument name as meta-data is what I personally find most interesting about Argible. The idea behind Argible should NOT be limited simply to Rails based applications. Anyone have ideas for other situation where this might be useful?
September 10, 2007
Shoes: Cross-platform Ruby GUI Toolkit
Tonight I attended the monthly Chicago Area Ruby Group. A fellow ThoughtWorker, Josh Cronemeyer, gave an overview of Why's Shoes project.
Many of the attendees seemed to question the need for a Ruby based HTML-like GUI toolkit. While Shoes is by no means ready, nor possibly even intended for, business applications I did find it interesting. A viable Ruby GUI toolkit would improve Ruby adoption even further. Of course JRuby and Swing integration could be sufficient enough to fill that gap (i.e. Swiby).
Many of the attendees seemed to question the need for a Ruby based HTML-like GUI toolkit. While Shoes is by no means ready, nor possibly even intended for, business applications I did find it interesting. A viable Ruby GUI toolkit would improve Ruby adoption even further. Of course JRuby and Swing integration could be sufficient enough to fill that gap (i.e. Swiby).
August 30, 2007
Are your Java projects misusing java.text.Format?
As a consultant with ThoughtWorks I get the opportunity to see many different code bases at a variety of client. A common mistake I see again and again is that developers do not realize that sub-classes of java.text.Format (e.g. NumberFormat, SimpleDateFormat) are not thread safe. If your project defines a static instance of a formatter, like so:
Then chances are you have a bug.
As is the case with many threading issues, this might not be easily identified because it probably doesn't happen consistently (we are at the mercy of the Thread Scheduler).
Recently on a project I created a test to prove that using such Formats can cause problems. We then fixed the issue and decided to keep the test in the code base to ensure that no developers 'accidentally' re-introduces it. NOTE: A Continuous Integration server, CruiseControl, ensures that our tests are run continuously.
Below is a simple, self-contained, test you can use to see the issue for yourself. Remember that the test might not fail every time because it is dependent on how the threads are scheduled. I have found that the test fails with more consistency when executed a single CPU (or single-core) machine.
public static final SimpleDateFormat SIMPLE_DATE_FORMAT
= new SimpleDateFormat("MM-dd-yyyy");
Then chances are you have a bug.
As is the case with many threading issues, this might not be easily identified because it probably doesn't happen consistently (we are at the mercy of the Thread Scheduler).
Recently on a project I created a test to prove that using such Formats can cause problems. We then fixed the issue and decided to keep the test in the code base to ensure that no developers 'accidentally' re-introduces it. NOTE: A Continuous Integration server, CruiseControl, ensures that our tests are run continuously.
Below is a simple, self-contained, test you can use to see the issue for yourself. Remember that the test might not fail every time because it is dependent on how the threads are scheduled. I have found that the test fails with more consistency when executed a single CPU (or single-core) machine.
import junit.framework.TestCase;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ThreadSafetyTest extends TestCase {
private static final SimpleDateFormat FORMAT
= new SimpleDateFormat();
public void testSimpleDateFormat() throws InterruptedException {
for (int i = 0; i < 50; i++) {
MyRunnable[] runnables = {
new MyRunnable(new Date(-1)),
new MyRunnable(new Date(1))
};
Thread one = new Thread(runnables[0]);
Thread two = new Thread(runnables[1]);
one.start();
two.start();
one.join();
two.join();
assertFalse("Values should not be equal",
runnables[0].value.equals(runnables[1].value));
}
}
private static class MyRunnable implements Runnable {
private Date date = null;
public String value = null;
MyRunnable(Date date) {
this.date = date;
}
public void run() {
value = FORMAT.format(date);
}
}
}
August 29, 2007
Argible: testing argible-ized actions
Last week Jay Fields and I were discussing Argible and he asked, "How's testing an action that uses Argible?", the answer ... easy.
Suppose we have the following Controller with an argible-ized action:
And here is the associated RSpec test:
You can see from the test that you do not need to do anything special to test your argible annotated action methods. Just call the action with whatever parameter name and values your action requires.
Suppose we have the following Controller with an argible-ized action:
class CalculatorController < ApplicationController
argible(:first => :to_i, :second => :to_i)
def add(first, second)
@result = first + second
end
end
And here is the associated RSpec test:
describe CalculatorController, "add action" do
controller_name :calculator
it "should add argument values" do
post :add, :first => "18", :second => "2"
controller.instance_variable_get(:@result).should == 20
end
end
You can see from the test that you do not need to do anything special to test your argible annotated action methods. Just call the action with whatever parameter name and values your action requires.
August 22, 2007
Blogger.com: unable to edit a post without publishing
Today I went back through my blog and added some labels (aka tags) to older posts. Soon afterwards I realized that adding these labels forced those post to be re-published. I found this annoying because visitors to sites like ThoughtBlogs would now have to sift through this "noise", obscuring the most recent post I'm most interested in sharing.
I think Blogger.com should provide a way to make minor edits to previously published posts without forcing these posts to be re-published. I understand that WordPress offers this functionality (right?). Is there a way this can be done that I might have missed? Or would I need to wait for such functionality to be introduced? Maybe it'll be easier if I just move my blog WordPress?
I think Blogger.com should provide a way to make minor edits to previously published posts without forcing these posts to be re-published. I understand that WordPress offers this functionality (right?). Is there a way this can be done that I might have missed? Or would I need to wait for such functionality to be introduced? Maybe it'll be easier if I just move my blog WordPress?
Argible: automatically set instance variables
As I discussed in my last post Argible makes it easy to resolve method argument values through simple convention. Peter Ryan had an excellent idea of using Argible to automatically set an instance variable's value through simple convention. Have a look at the example below:
Notice that the action method, action_one, has NO arguments. But the argible annotation was passed :foo => :@bar. Argible will interpret that you want the resolved value of 'foo' to be set upon the instance variable named '@bar'. This happens because the symbol on the right hand side is prefixed with the character '@'. Without this Argible will raise an Error informing you that there is no such argument.
class MyController < ApplicationController
argible(:foo => :@bar)
def action_one
p "Bar instance variable was set to: #{@bar}"
end
end
Notice that the action method, action_one, has NO arguments. But the argible annotation was passed :foo => :@bar. Argible will interpret that you want the resolved value of 'foo' to be set upon the instance variable named '@bar'. This happens because the symbol on the right hand side is prefixed with the character '@'. Without this Argible will raise an Error informing you that there is no such argument.
August 20, 2007
Introducing Argible: Simplifing your Ruby on Rails Controllers
Argible is a RubyForge project that was created to simplify Action methods within your Ruby on Rails Controllers. Argible annotated action methods will allow your Actions to define argument. These argument names will be used in conjunction with request parameters to automatically resolve these argument values. Have a look at the FoobarController code below:
The first method action_one(alpha) is annotated with the method argible. When the action_one method is executed Argible will intercept the call and look up the request parameter value associated with alpha. Next the action_one method will be called with this resolved value.
The second action, action_two(date), provides an example of how more complex processing can occur on argument values. As in the first example the argument, this time named date, is resolved against the request parameters. The resulting value will then be passed to the Date#parse method. The result from Date#parse will then be used when action_two is called. **NOTE: any method can be used, Date#parse is simply used as an example.
The action action_three(date) provides an example of using a Proc (lambda) as alternative to a named method.
The fourth example action action_four(value) illustrates how you can call methods directly on the string value returned from
the request parameter.
Argible 0.1.0 is available for immediate use from http://rubyforge.org/projects/argible. RDoc can be found at http://argible.rubyforge.org.
class FoobarController < ApplicationController
argible
def action_one(alpha)
...
end
argible(:date => Date.method(:parse))
def action_two(date)
...
end
argible(:date => lambda {|v| Date.parse(v) } )
def action_three(date)
...
end
argible(:value => :to_i)
def action_four(value)
...
end
end
The first method action_one(alpha) is annotated with the method argible. When the action_one method is executed Argible will intercept the call and look up the request parameter value associated with alpha. Next the action_one method will be called with this resolved value.
The second action, action_two(date), provides an example of how more complex processing can occur on argument values. As in the first example the argument, this time named date, is resolved against the request parameters. The resulting value will then be passed to the Date#parse method. The result from Date#parse will then be used when action_two is called. **NOTE: any method can be used, Date#parse is simply used as an example.
The action action_three(date) provides an example of using a Proc (lambda) as alternative to a named method.
The fourth example action action_four(value) illustrates how you can call methods directly on the string value returned from
the request parameter.
Argible 0.1.0 is available for immediate use from http://rubyforge.org/projects/argible. RDoc can be found at http://argible.rubyforge.org.
July 26, 2007
Run your JRuby RSpec tests from Maven
On my most recent project we made heavy use of RSpec. After 6+ months of using it I must admit that I am a big fan. Therefor I was very happy to see that JRuby included RSpec within its distro (see JRuby bundles RSpec).
I have also been working on adding JRuby support for Waffle. So I decided to write my Ruby tests for Waffle with RSpec. Additionally, I wanted these RSpec tests to run as part of the build. Waffle, like many Java open source projects, uses Maven 2. Regardless of whether you love or hate Maven its dependency and repository convention have became a standard way to easily distribute jars. So I wrote an Maven plug-in that allows you to execute your RSpec tests from Maven. We have since contributed this to Codehaus' Mojo Project. So give it a look if you have the need.
** Ruby support within Waffle will allow developers to write their Controllers, and other objects, with straight Ruby syntax. Look for more info on this functionality soon.
I have also been working on adding JRuby support for Waffle. So I decided to write my Ruby tests for Waffle with RSpec. Additionally, I wanted these RSpec tests to run as part of the build. Waffle, like many Java open source projects, uses Maven 2. Regardless of whether you love or hate Maven its dependency and repository convention have became a standard way to easily distribute jars. So I wrote an Maven plug-in that allows you to execute your RSpec tests from Maven. We have since contributed this to Codehaus' Mojo Project. So give it a look if you have the need.
** Ruby support within Waffle will allow developers to write their Controllers, and other objects, with straight Ruby syntax. Look for more info on this functionality soon.
May 22, 2007
Waffle Haus ...
Waffle is moving from SourceForge to Codehaus. Additionally, and more importantly Waffle and VRaptor teams have decided to join forces.
The Waffle web framework will provide the core architecture for this joint effort. As the first step we have has begun porting Waffle to Codehaus (renaming it to use org.codehaus.waffle package instead of com.thoughtworks.waffle). Next we will begin to gradually port features from VRaptor. The vision of this effort is to create a larger and more consolidated community around a lean web application framework which honours the least-common-denominator principle.
The Waffle web framework will provide the core architecture for this joint effort. As the first step we have has begun porting Waffle to Codehaus (renaming it to use org.codehaus.waffle package instead of com.thoughtworks.waffle). Next we will begin to gradually port features from VRaptor. The vision of this effort is to create a larger and more consolidated community around a lean web application framework which honours the least-common-denominator principle.
March 20, 2007
RSpec:Rails - How to mock partials when testing a View.
When developing Ruby on Rails (RoR) applications I prefer to use RSpec over the built in testing framework provided with RoR. The biggest benefit is that RSpec easily allows you to test your application layers in isolation (e.g. when testing a Controller you should not be interested in testing the Model). So with that in mind when I am testing a View I am only interested in testing that View and not any of the potential partials that View may try to render.
Suppose we have the View /example/hello_world.rhtml:
Often in RSpec when testing a view such as this the spec ends up testing the partial as well. This is less than desirable because any change to the partial could break test for other views that render that partial. After some investigation I discovered that I could mock the calls to <%= render :partial => 'address'... %>. Have a look at the following spec:
You can grab a handle to the ActionView through @controller.template as is done in the example above. Then I mock the call to the 'render' method only when the 'address' partial is requested.
As you can see my spec only needs to be concerned with testing the /example/hello_world.rhtml View. The partial will have it's own separate spec. The side effect is that my view specification becomes much more manageable and far less brittle.
Suppose we have the View /example/hello_world.rhtml:
<div id="person">
<h2 class="title">Hello <%= @person.name %></h2>
<%= render :partial => 'address', :locals => {:person => @person} %>
</div>
Often in RSpec when testing a view such as this the spec ends up testing the partial as well. This is less than desirable because any change to the partial could break test for other views that render that partial. After some investigation I discovered that I could mock the calls to <%= render :partial => 'address'... %>. Have a look at the following spec:
specify 'should call mock and not the actual partial' do
person = mock('person')
person.should_receive(:name).and_return('Regan')
assigns[:person] = person
# Mock the call to 'render_partial'...
@controller.template.should_receive(:render).with(:partial => 'address', :locals => {:person => person})
render '/example/hello_world'
response.should_have_tag(:h2, :content => "Hello Regan")
end
You can grab a handle to the ActionView through @controller.template as is done in the example above. Then I mock the call to the 'render' method only when the 'address' partial is requested.
As you can see my spec only needs to be concerned with testing the /example/hello_world.rhtml View. The partial will have it's own separate spec. The side effect is that my view specification becomes much more manageable and far less brittle.
October 05, 2006
ParaNamer support in Waffle as an alternative to annotations
The latest release of Waffle (0.7) can now fully support ParaNamer as an alternative to annotations. ParaNamer provides "method parameter name access for versions of Java PRIOR TO Java 7.0". ParaNamer combined with Waffle will allow you to utilize your ActionMethod parameter names directly. In the example below Waffle will use "itemId" and "quantity" to resolve the arguments for the void removeFromCart(Long, int) action method.
For complete details on this please see the documentation on Waffle ActionMethods.
public class ShoppingCartAction implements Serializable {
...
// No annotation is necessary when utilizing ParaNamer
public void removeFromCart(Long itemId, int quantity) {
cart.remove(itemId, quantity);
}
}For complete details on this please see the documentation on Waffle ActionMethods.
October 04, 2006
Describing Waffle with one picture
The Waffle team has been busy over the last few months adding features and simplifying the overall design. Much of the documentation has been updated to reflect these changes. Many times however, it is easier to describe something with a simple drawing or a picture. So have a look at the following to get a clear idea of what Waffle provides:
Ruby on Cygwin error (*** unable to remap)
I had an annoying issue occuring when running Ruby under Cygwin. The error was reproducable every time that I attempted to run the ri command.
I was finally able to resolve the issue with the following steps:
C:\cygwin\lib\ruby\1.8\i386-cygwin\readline.so to same address as parent(0x370000) != 0x2760000
C:\cygwin\bin\ruby.exe (3132): *** unable to remap C:\cygwin\lib\ruby\1.8\i386-cygwin\readline.so to same address as parent(0x370000) != 0x2760000
I was finally able to resolve the issue with the following steps:
- exit from cygwin
- enter the dos command prompt
- cd to you cygwin bin directory (c:\cygwin\bin)
- run ash rebaseall
- restart cygwin ... problem solved
June 19, 2006
Waffle: define a default event in your Action
Waffle now provides a new DefaultEvent method level annotation for use in your Actions. This allows you to mark a particular method as the default event to fire when no other event was signalled. This is particularly useful when a user is directed to a page for the first time. Until now, the previous page was responsible for setting up for the page that preceeds it. Either that or all links within your application would be required to define exactly which event should be triggered through request parameters (e.g. "/application/myaction.htm?EVENT=init|{request}").
The following Action example (MyAction) has its init(HttpServletRequest) method annotated as the default event.
Notice the value "{request}" set on the DefaultEvent annotation. This provides a hint to Waffle to help it satisfy the method arguments. If you are familiar with Waffle you should realize that this is similar to how events are defined from Views. This in fact is not just similar it is identical. You can define the event arguments for the DefaultEvent annotation in the same way described in the Advanced Events section of the tutorial.
The following Action example (MyAction) has its init(HttpServletRequest) method annotated as the default event.
public class MyAction {
@DefaultEvent("{request}")
public void init(HttpServletRequest request) {
// ...
}
}
Notice the value "{request}" set on the DefaultEvent annotation. This provides a hint to Waffle to help it satisfy the method arguments. If you are familiar with Waffle you should realize that this is similar to how events are defined from Views. This in fact is not just similar it is identical. You can define the event arguments for the DefaultEvent annotation in the same way described in the Advanced Events section of the tutorial.
April 19, 2006
Waffle on TheServerSide.com
Waffle was recently posted on TheServerSide.com under the heading Another Rails-like web framework: Waffle. I was happy to see it posted and really appreciated the responses from those that are interested in Waffle.
I'm grateful for the comparison of Waffle to Ruby on Rails but Waffle is NOT a Java version of Rails. I think the only viable comparison I can make between Waffle and Ruby on Rails is:
I'm grateful for the comparison of Waffle to Ruby on Rails but Waffle is NOT a Java version of Rails. I think the only viable comparison I can make between Waffle and Ruby on Rails is:
- convention based
- simplicity
- both take advantage of their respective languages
- increased development productivity
March 28, 2006
Try using FreeMarker to generate XML documents
Generating XML from code is a very common development task. There are a multitude of ways it can be accomplished. Recently, at a client, we needed to generate an XML message which had to conform to a rather complicated XML schema. We already had an object model that worked well with our code base. We considered using XML binding API's like:
Each of these had its own limitations which reduced their feasibility within our application. Next we considered hand-coding the XML directly with API's like:
The amount of code required to create an XML document with these API's was excessive. Code like this was not fun to write nor easy to follow.
So we decided to take a different approach and use a templating engine, specifically FreeMarker. Using FreeMarker to generate the XML response messages turned out to be a great decision. This is a list of some of the advantages we have noticed:
Each of these had its own limitations which reduced their feasibility within our application. Next we considered hand-coding the XML directly with API's like:
The amount of code required to create an XML document with these API's was excessive. Code like this was not fun to write nor easy to follow.
So we decided to take a different approach and use a templating engine, specifically FreeMarker. Using FreeMarker to generate the XML response messages turned out to be a great decision. This is a list of some of the advantages we have noticed:
- The FreeMarker template we wrote to create the XML response message is an XML document. This simple fact should not be overlooked.
- Easy to integrate into any application. Very little code was required to utilize FreeMarker in our application.
- Excellent performance.
- The built-in functionality that FreeMarker provides is very powerful.
Tutorials for Waffle
I have been spending my free time updating Waffle with functionality and documentation. Two tutorials have been added to the Waffle web site which should provide a good overview of how to use Waffle and what makes it different.
The examples in the tutorials show how to use Waffle with JSP's. This was done based on feedback I have had when talking about Waffle with developers. At this point you should get latest Waffle code directly from subversion and build it with Maven 2.0.
I would appreciate any comments or feedback you could offer.
The examples in the tutorials show how to use Waffle with JSP's. This was done based on feedback I have had when talking about Waffle with developers. At this point you should get latest Waffle code directly from subversion and build it with Maven 2.0.
I would appreciate any comments or feedback you could offer.
February 22, 2006
Sourceforge and subversion
I logged into SourceForge.net today and noticed that a Subversion link was now available when I went to the Administration page. I'm not sure when this feature became available or how long it took me to actually notice it but I think it is great news that SourceForge now provides it.
Look for Waffle's code base to be moved to Subversion shortly.
Look for Waffle's code base to be moved to Subversion shortly.
February 14, 2006
FreeMarker support in Waffle
I recently added FreeMarker support as another option for creating Views in Waffle. FreeMarker is very similar to Velocity but seems to be more powerful. One of the nice features of FreeMarker is that it will point out the errors in your scripts. Velocity basically ignores any problems you may have, while FreeMarker displays an error message directly in your html that pin-points (line and column number) where the problems is located. Additionally FreeMarker actually allows you to reference JSP tag libraries within your FreeMarker scripts. That should allows for some nice flexibility. Take a look at the FreeMarker Servlet Documentation for further details. And take look at Waffle to see how easy it is to create web frameworks when you don't have to learn a proprietary XML syntax or new UI language.
Next task is to document how to create Waffle application with JavaServer Pages (JSP).
Next task is to document how to create Waffle application with JavaServer Pages (JSP).
January 26, 2006
The Glacial Methodology
The Waterfall Methodology is making a comeback in a big way. Hurry and register when you can ...
http://www.waterfall2006.com/
http://www.waterfall2006.com/
Subscribe to:
Posts (Atom)