Apotomo 1.1 released!

“Apotomo”:http://github.com/apotonick/apotomo, the *web components framework for Rails*, got 1.1 today and we’re more than happy to announce nothing but *massive simplifications for users* and conventional changes.


h3. What happened?

The framework core got a slimming cure. *We threw out 50% of the code* and it still does the very same as before – this is nothing to worry about, just read on.

* *Convention over configuration* found its way into Apotomo, widgets now have a *conventional @Widget@ suffix* (and more).
* *State-args* are now heavily used in Apotomo (as known from “Cells”:http://nicksda.apotomo.de/2011/02/cells-3-5-release-party-summary/). For instance, triggered states receive the event object as argument.
* *Rendering children widgets* got nothing more than calling @#render_widget@ – as it’s done in controller views.
* *Start states* were removed. Nobody needs it.
* *Statefulness* got separated to its own gem. This reduces complexity in the core.

h3. Will it break my code?

In the *worst case you gotta move your widgets to their new residence*, rename a couple of directories and change calls to @#param@ back to @#params[]@.

However, we got a lot of *sweeeet improvements*.

h3. Convention over Configuration

This change was initiated by some famous Rails celebrity, recently. In a “public discussion”:http://groups.google.com/group/cells-and-apotomo/browse_thread/thread/9ca3cfac57825db7 the pseudo-democratic regime finally decided to introduce *the following changes to the widget file layout*.

$ rails g apotomo:widget Cart display -e haml
  create  app/widgets/cart_widget.rb
  invoke  haml
  create    app/widgets/cart/display.html.haml
  invoke  test_unit
  create    test/widgets/cart_widget_test.rb

* *Widgets now reside in @app/widgets/@* to prevent mixing things with plain cells.
* Notice how the @_widget@ suffix is appended per convention. This means all your widgets _must_ have that suffix (otherwise, you need to change things a bit).
* Views used to live in something like @app/cells/cart_widget/@, they *are now at @app/widgets/cart@.* That’s how things already work with controllers, models, cells, and more.
* The *widget generator* now is a good rails citizen and provides hooks for template engine and test framework. BTW- we’re “soon” gonna release rspec-apotomo, if that is what you’re looking for.

These changes have a couple of nice side effects.

h3. Save the earth, plant a widget tree.

In earlier times the *widget tree setup always happened to look a bit clumsy*.

class DashboardController < ApplicationController
  include Apotomo::Rails::ControllerMethods
  has_widgets do |root|
    root << widget(:cart_widget, 'your_cart', :show)

You had to pass the class, an id and *a mysterious _start state_*. This now looks a bit simpler.

class DashboardController < ApplicationController

  has_widgets do |root|
    root << widget(:cart)

Simpler, isn’t it?

* You can skip the @include Apotomo::…@ part, *Apotomo will automatically its controller module* into the widget controller. Don’t worry, no other controller will be harmed.
* Apotomo *set the widget id to @:cart@*. Did you notice how the convention saved you from typing the suffix, also?

Now what if I want another id for my Rails widget? Maybe we need a second cart widget?

  has_widgets do |root|
    root << widget(:cart)
    root << widget(:cart, 'your_private_cart')

Rendering widgets still requires you to pass the id.

  = render_widget :cart
  = render_widget 'your_private_cart'

Simpler, isn’t it?

h3. Nobody needs start states.

You may wonder what happened to the start states. The answer is: Start states survived from the times when Apotomo was a *Modeldrivenarchitecture-generic-widgets-with-integrated-statemachines-and-space-simulator-beast*. Useless crap.

  = render_widget :cart

will invoke the *conventional @#display@ state* on the widget. Pass the state explicitely if you want something _else_.

  = render_widget :cart, :show

Simpler, isn’t it?

h3. Rendering the kids.

Until today *Apotomo did a horrible job trying to render children* automatically in a widget. There was this @rendered_children@ hash in the view and, oh come on, let’s just forget that and see how it works now.

  My family:
  - children.each do |kid|
    = render_widget kid

Just *use @#render_widget@ in a state view* and you’re done.

Or maybe just a single child?

  = render_widget 'billy-the-kid'

That’s all. Pass whatever state-args options you like.

Simpler, isn’t it?

h3. Using options for configuration.

Often you need to *stick configuration to widget instances*. You may do that in the @has_widgets@ block.

  has_widgets do |root|
    root < "light")

This hash will be *available in _any_ state* using the new @#options@ method from Cells.

class CartWidget < Apotomo::Widget
  def display
    @theme =  options[:theme] || "sunset"

Note that this also works in triggered states! What happens in the @has_widgets@ block is available anywhere.

h3. State-args FTW!

Since state-args were introduced in Cells *I _love_ them!* They make things so much easier and ruby-like. They basically allow *passing locals to a state*.

= render_widget :cart, :display, current_user.admin?

Note how you can set default values in the state, which is awesome.

  def display(is_admin=false)
    raise "Admins do not shop!" if is_admin

Even cooler, *triggered states can receive the bubbling event* instance.

  responds_to_event :submit

  def submit(evt)

Hey, that’s cool, @responds_to_event@ *doesn’t require a trigger state name* anymore if it’s identical to the event name.

So, how does that event argument help us? Actually, it helps twice!

h3. Where is #param?

Luckily, we removed @#param@. It sucked.

*If you need global request parameters*, use @#params[]@.

However, *in a good component-oriented design* you shouldn’t need to access global parameters _inside_ widgets.

  = url_for_event :submit, :item_id => item.id

Now, why not query the event for request parameters.

  def submit(evt)
    item = Item.find evt[:item_id]

You’re still reading request parameters, but from a local event object – definitely better.

h3. Using the event for message passing.

When triggering an event it sometimes *makes sense to add some payload data*. Consider that triggering state somewhere.

class Cart::ItemsWidget  @items

Another widget interested in that event can use *_state-args_ to grab the event*.

class Cart::CheckoutWidget < Apotomo::Widget
  responds_to_event :items_changed

  def items_changed(evt)
    items = evt[:items]

Get the *event as argument and use @#[]@* to access its payload.

Simpler, isn’t it?

h3. Use it!

That was a not-so-brief overview. *We strongly encourage you to upgrade.* It’s actually _fun_ using the new features and will make your code even cleaner. Tell us if you like it.




8 thoughts on “Apotomo 1.1 released!

  1. Brilliant changes, Nick. The clarity is priceless.
    The required changes were so simple to make.
    I offer one addition to “Will it break my code ?”
    You also have to change the widget test.
    This :
    root << widget(:my_name_widget, ‘me’)
    to this :
    root << widget(:my_name, ‘me’)


  2. @Spyros: Yeah, some other greek guys already told me πŸ˜€ It’s an abbreviation with greek meaning by accident, but I like it!

    @Clemens: Dude I was trying to email you to ask about the rights for that pic but found out I DON’T HAVE YOUR EMAIL!!!

    @anon: Clemens is not affiliated with Apotomo, so don’t put him in the shortbus! BTW, your breath stinks and your dick is too short haha


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s