iBrasten

My methods of calculating time are far superior to yours, in every way.

 

This is the blog of Brasten Sager, a freelance software developer, Mariners fan, guitarist, haphazard philosopher.

This wasn't a problem in Java...

September 29, 2006 @ 02:07 AM

... which makes this my strongest argument to date for using Java instead of Ruby. :)

Portland updated on Google Maps.

September 27, 2006 @ 09:14 AM

Not sure how long ago this happened, but it appears some fairly recently satellite photos of Portland have been taken and updated on Google Maps.

It’s probably been a week or two since I last visited Portland on Google Maps, but their photos were horribly outdated, especially in the Pearl District area.

In the previous photos, the Pearl was mostly ripped apart (particularly the northern sections), but you’re now able to see the completed Tanner Springs Park, the Pinnacle building, and many others that did not exist on the older photos.

Nagilum on the move!

September 25, 2006 @ 05:02 AM

Good things happening with myself and Nagilum LLC.

Firstly, Nagilum LLC and Digital Possibilities Inc. have jointly reserved office space in the Fremont area of Seattle. Since Nagilum LLC only needed enough space for myself (at the moment), I was thrilled to hear DigiPoss needed a second office location and was looking in the same area I was. If all goes as planned, we will be moving in upon completion of the building (the Fremont Space Building on N 36th St.) in November.

On a personal level, I’m very excited to get Nagilum LLC out of my home office and into a real one. It’ll be good to get out and be around very smart, highly creative people on a consistent basis.

Secondly, I’m getting all my ducks in a row to increase the visibility and capabilities of Nagilum LLC once we’re in the new office. I’ve got a new website design nearly completed for www.nagilum.com which will likely go live in November. I’m also preparing for the possibility of bringing on more Ruby developers and/or graphic designers.

So, fun times indeed.

Topfunky Red Rover Ruby Speakers Series

Anyone else going tomorrow night? I’ll be there!

TextMate tip - scope your project!

September 21, 2006 @ 01:31 PM

If there’s one tool that I cannot live without these days, it’s TextMate. In particular, the “mate” command has been a lifesaver. A simple “mate .” command in my Rails directory and I’m on my way!

The downside to that approach is that often I do not need to focus on the entire application. Sometimes having the entire Rails project visible/available in TextMate can create mental clutter (upper screenshot).

So I tried creating several aliases for “mate” that open just the files I’d most likely need for a particular case. For example, most of my development now is done using this alias:

alias mt="mate app/controllers/ \
          app/models/ app/views/ test/ \
          db/migrate/ config/routes.rb" 

Now, “mt” in my project directory gives me a TextMate project with only the most relevant directories and files (lower screenshot).

Rest Controller plugin

September 20, 2006 @ 07:35 AM

I’ve been using this in my recent projects fairly successfully, so I’m putting it out there for anyone else to use.

Rest Controller (unoriginal name, I know) provides basic defaults for your 7 RESTful actions (index, show, edit, new, create, update, destroy) for both HTML and XML. There are some basic customization capabilities, but if you need to customize more than a couple things, you shouldn’t be using this plugin.

Installation

If you haven’t included svn.superruby.com in your plugin sources:
  script/plugin discover
  # Yes to http://svn.superruby.com/svn/plugins/
Finally:
  script/plugin install rest_controller

From the README

Rest Controller provides basic default actions for a RESTful controller which can be overridden easily.

There is basic customization capabilities of the default responses. If you need more customization, you should just implement the method in question to bypass this plugin. If you find yourself overriding more than one or two of the default methods, then you probably should not be using this plugin to begin with.

Usage

1
2
3
4
    # Controller with default actions.
    class ProductsController < ApplicationController
      rest_controller :product
    end

Default Actions/Responses

These examples use @product / @products, but your actual variable name will depend on the model. “rest_controller :customer” will result in @customer / @customers, for example.

Index      - find(:all) on your model.
  HTML --> renders index.rhtml
  XML  --> renders @products.to_xml
  RNG  --> renders @products.to_rng (if simply_relaxed plugin is installed.)

Show       - find(params[:id])
  HTML --> renders show.rhtml
  XML  --> renders @product.to_xml if found / Status Code 404 if not.

Edit       - find(params[:id])
  HTML --> renders edit.rhtml

New        - Model.new
  HTML --> renders new.rhtml

Update     - update(params[:id], params[:product])
  HTML --> sets flash[:notice] appropriately
           redirects to show(id) if successful / renders edit.rhtml if not
  XML  --> Status Code 204 if successful / Status Code 400 if not

Create     - create(params[:product])
  HTML --> sets flash[:notice] appropriately
           redirects to show(id) if successful / renders new.rhtml if not
  XML  --> Status Code 201 if successful / Status Code 400 if not

Destroy    - destroy(params[:id])
  HTML --> sets flash[:notice] appropriately
           redirects to index
  XML  --> Status Code 204 / Status Code 404

Overriding Responses You can override the default responses by either providing a custom respond_to block, or provide a block for a specific action/mime-type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    # Overriding some responses.
    class ProductsController < ApplicationController
      rest_controller :product

      # Override a DELETE/HTML response.
      destroy_responds_to(:html) { render :text => "GONE!" }

      # ... could also be formatted this way ...
      destroy_responds_to :html do
        render :text => "GONE!"
      end

      # Override all default responses for an action with a custom
      # respond_to block.
      show_responds_to do |wants|
        wants.html
        wants.xml { render :xml => @product.to_xml(... some includes ...) }
        wants.graph { ... }
      end
    end

If you need to customize the logic for a particular action and cannot accomplish your desired result with before/meantime filters, you can simply implement the action in your class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    # Implement your own actions.
    class ProductsController < ApplicationController
      rest_controller :product

      # Overrides the 'update' action.
      def update
        # Do something special for updating.
      end

      # You can trigger the default responses, if they still
      # apply.
      def index
        # Some special code.
        index_responder
      end
    end

Responders expect an instance variable by the name of the model. (Product == @product, etc). index expects the plural name (@products).

Simply Relaxed Rails plugin

September 15, 2006 @ 03:55 PM

Well, I swear I don’t sit around all day writing plugins. I just happened to finalize a couple of these things today. :)

What is Simply Relaxed?? Simply Relaxed converts your models into a RELAX NG schema. Not much more to say.

Installation

  script/plugin discover

  # Say yes to http://svn.superruby.com/svn/plugins

  script/plugin install simply_relaxed

Examples

1
2
3
4
5
6
7
8
9
10
class OrdersController < ApplicationController
  def index
        @orders = Order.find(:all)

    respond_to do |wants|
      wants.xml { render :xml => @orders.to_xml }
      wants.rng { render :xml => Order::to_rng }
    end
  end
end
URL: http://localhost:3000/orders.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
<orders>
  <order>
    <id type="integer">1</id>
    <placed-at type="datetime">2006-09-13T09:35:40-07:00</placed-at>
    <status>ACTIVE</status>
    <total-amount type="decimal">150.25</total-amount>
    <total-double type="float">150.25</total-double>
    <total-float type="float">150.25</total-float>
    <user-id type="integer"></user-id>
  </order>
  <order>
    <id type="integer">2</id>
    <placed-at type="datetime"></placed-at>
    <status>PENDING</status>
    <total-amount type="decimal">0.0</total-amount>
    <total-double type="float"></total-double>
    <total-float type="float"></total-float>
    <user-id type="integer"></user-id>
  </order>
</orders>
URL: http://localhost:3000/orders.rng
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?xml version="1.0" encoding="UTF-8"?>
<grammar datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes" 
         xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <choice>
      <element name="orders">
        <zeroOrMore>
          <ref name="order"/>
        </zeroOrMore>
      </element>
      <ref name="order"/>
    </choice>
  </start>
  <define name="order">
    <element name="order">
      <zeroOrMore>
        <choice>
          <element name="placed-at">
            <attribute name="type"/>
            <optional>
              <data type="dateTime"/>
            </optional>
          </element>
          <element name="status">
            <optional>
              <text/>
            </optional>
          </element>
          <element name="total-amount">
            <attribute name="type"/>
            <optional>
              <data type="decimal"/>
            </optional>
          </element>
          <element name="total-double">
            <attribute name="type"/>
            <optional>
              <data type="float"/>
            </optional>
          </element>
          <element name="total-float">
            <attribute name="type"/>
            <optional>
              <data type="float"/>
            </optional>
          </element>
          <element name="user-id">
            <attribute name="type"/>
            <optional>
              <data type="integer"/>
            </optional>
          </element>
        </choice>
      </zeroOrMore>
    </element>
  </define>
</grammar>

Jactive! -- ActiveResource for Java

September 15, 2006 @ 07:09 AM

I plan on giving more detail about this later, but I put together a little library for using ActiveResource objects in Java. Actually, I guess ActiveResource is the client API, so it’s more like a Java port of ActiveResource compatible with the Rails REST services.

For the examples below, I’ve hacked out things like the imports and getters/setters. So these obviously won’t compile as-is.

Order.java (Model):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import com.nagilum.jactive.*;
import com.nagilum.annotation.*;

@Resource(resourceName="orders")
public class Order implements ActiveResource {
    
    private @ResourceConnector static Connector connector;
    
    private @Attribute int id;
    private @Attribute String status;
    private @Attribute double totalAmount;
    
    public Order save() throws Exception {
        return (Order) connector.save(this);
    }
    
    public Order delete() throws Exception {
        return (Order) connector.delete(this);
    }
    
    public static Order find(int id) throws Exception {
        return (Order) connector.find(Order.class, id);
    }

    (accessor methods for attributes)
}
Example of Jactive in use:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Connector connector = new Connector("http://localhost:3000/");
connector.registerResource(Order.class);

// Finding/Updating works
Order order = Order.find(1);
order.setStatus("PENDING");
order.save();

// Creating new resources works
Order newOrder = new Order();
newOrder.setStatus("NEW");
newOrder.setTotalAmount(150.00);
newOrder = newOrder.save();

// Update new order
newOrder.setStatus("APPROVED");
newOrder.save();

// We're done here.
newOrder.delete();
order.delete();

Coming soon…

To answer a few anticipated questions:

  • Jactive is open-source. I will release the source shortly.
  • All of that actually works right now.
  • I will be adding findAll() soon.
  • You don’t HAVE to implement the ActiveResource interface if you don’t want to (say, if you have existing value objects). If you don’t, the Connector will act as a DAO. Example: connector.save(order);
  • Most importantly, Jactive is NOT attempting to be compatible with some or all hypothetical REST implementations. The purpose of Jactive is to be compatible with Rails’ REST implementation. Period. Hence, Jactive. Not, JEST.

NilHash Plugin

September 13, 2006 @ 01:40 PM

This is such a stupidly simple plugin, it’s barely worth a post. BUT

NilHash prevents chained element references from raising NoMethodErrors by provided NilClass with a limited \[\]\(key\) method.

Before:
1
2
3
4
5
6
# There are many ways to do this, here's just one.
def some_action
  return if (params[:order].nil? || 
             params[:order][:address].nil? || 
             params[:order][:address][:zip_code].nil?)
end
With NilHash:
1
2
3
def some_action
  return unless params[:order][:address][:zip_code]
end

Originally I sent this as a patch to the core team, but apparently this constitutes a “major change in behavior.” I would be interested in knowing if anyone has any problems after installing this. I don’t yet see how it’s a major behavioral change.

Installation

  # Make sure to say Y to http://svn.superruby.com/svn/plugins/
  $ script/plugin discover

  $ script/plugin install nil_hash

New Business Cards!

September 08, 2006 @ 08:04 AM

The new business cards came just in time for the Sun TechDays conference yesterday (which, by the way, was a horribly dull experience).

I was very pleased with the design we came up with, and the printers did an amazing job. Here’s a look.

Scruffy is alive and kicking...

September 06, 2006 @ 03:49 PM

It’s been a little while since I’ve said anything about Scruffy or rolled out a release. Like all of you, I have bills to pay, so I’ve been squeezing in Scruffy time around client’s projects. I was hoping to release the next version of Scruffy a few days ago, but it looks like it will be next week sometime before that happens.

In the meantime, let me tell you about some of the things you can expect in Scruffy 0.3.0.

Pie Charts! I’ve been promising these for a while, and they will be here. A.J. has done some fantastic work on these, and I’m really excited to get this functionality in your hands and see what you people do with it. The extra time has allowed A.J. to add in some really amazing capabilities.

For a demonstration, check out Ms. Scruffy. Ms. Scruffy was made entirely with pie charts, using some very simple options (offsets and pie-slice exploding, etc). Ms. Scruffy does not actually convey any useful information.

Customization API! While A.J. has been working on pie charts, my entire focus has been on building a really nice user-facing API—something Scruffy is weak at right now. Everything from legend location and orientation, x-axis and y-axis labels and locations, and many other options will be easily setable.

Additionally, graph layouts will shift to best accommodate your options. If you hide the legend, the graph will expand to fill that space. This stuff should be really cool!

Some other cool stuff! A lot of this is changing from day to day, so I’m just going to show some actual code I’m working on right now.

1
2
3
4
5
6
7
8
9
10
11
12
13
# Rails View Helpers
<%= scruffy :performance_graph, @agent %>

# A graph is just a representation of data.
def user
  @user = User.find params[:id]

  respond_to do |wants|
    wants.html
    wants.xml
    wants.graph   # renders user.rgraph
  end
end

Soon….