My Classes Can't Use Shoes Methods Like Para

How to use classes in Shoes?

I'm not too familiar with Shoes, but the problem you're likely having here is that you're trying to call a method called para on the Post class, and no such method exists.

When you call Shoes.app do ..., I suspect Shoes is changing the current execution context to one that includes those methods. That is, you should expect this to work:

Shoes.app do
para "The author of all posts is Jimmy"
end

This is equivalent to:

Shoes.app do
self.para("The author of all posts is Jimmy")
end

When you call Post.print_author, self is no longer the Shoes object, but rather, is the Post class. You have a few options at that point:

  1. Pass in the Shoes instance, and call your Shoes-specific methods on that. You should probably do it this way when you don't need any state from Post:

    class Post
    def self.print_author(shoes)
    shoes.para "The author of all posts is Jimmy"
    end
    end

    Shoes.app do
    Post.print_author(self)
    end
  2. Create a Post class which accepts a Shoes object, so you don't have to keep passing it around. You should do it this way if Post is going to have any substantial amount of state:

    class Post
    def initialize(shoes)
    @shoes = shoes
    end

    def print_author
    @shoes.para "The author of all posts is Jimmy"
    end
    end

    Shoes.app do
    post = Post.new(self)
    post.print_author
    end
  3. You could use a variant on the 2. option to automatically pass calls to the @shoes object. This starts to get into Ruby metaprogramming, which I'd recommend you avoid until you're more comfortable in Ruby, but I'm leaving it here to pique your interest:

    class Post
    def initialize(shoes)
    @shoes = shoes
    end

    def print_author
    para "The author of all posts is Jimmy"
    end

    def method_missing(method, *args, &block)
    @shoes.send(method, *args, &block)
    end
    end

    Shoes.app do
    post = Post.new(self)
    post.print_author
    end

What this does is tell Ruby "if a method isn't found on the Post instance, try sending it to the @shoes instance instead". As you can imagine, this can allow for some very nice DSLs, but you have to use it carefully, as it can make code difficult to follow if you abuse it.

How to call Shoes methods from inside an instance method?

Shoes.app { ... } does an instance_eval of the code block. What that means is the that the body of the block gets executed as though self were an instance of Shoes (or whatever class it is using under the hood). What you'll want to do is something like the following:

class MyClass
def initialize(app)
@app = app
end
def draw
@app.oval :top => 100, :left => 100, :radius => 30
end
end

Shoes.app {
myclass = MyClass.new(self) # passing in the app here
myclass.draw
}

How can I subclass in Shoes?

Let me guess, you're trying to do something like this:

class MyClass < Shoes

stack :width => 200 do
subtitle 'People who like ponies'
para 'TheTXI'
para 'Pesto'
para 'Einstein'
end

stack :width => -200 do
subtitle 'People who hate ponies'
para 'Hitler'
para 'Stalin'
para 'Einstein (He was bipolar)'
end
end

Well of course this doesn't work. para, stack, subtitle, and so on are all instance methods, but you're trying to call them as class methods. They have to be inside an instance method, like this:

class MyClass < Shoes
url '/', :pony_list

def pony_list
stack :width => 200 do
subtitle 'People who like ponies'
para 'TheTXI'
para 'Pesto'
para 'Einstein'
end

stack :width => -200 do
subtitle 'People who hate ponies'
para 'Hitler'
para 'Stalin'
para 'Einstein (He was bipolar)'
end
end
end

Shoes.app :width => 400

See how that stuff is in the pony_list method now? Of course, we have to make an instance call the method. How can we do that? That's why we call the url method (which, unlike para and its friends, actually is a class method). It sets the default url to call the pony_list method. Remember that you have to call Shoes.app after your class definition and you're all set.

Centring a flow in Shoes

Not completely sure. What is it in your flow you are trying to centre? You can try a margin left trick as per HTML and CSS.

This gives a flow with left, centre and right justified text that remains centred in the window as it is resized:

Shoes.app do
flow do
style(:margin_left => '50%', :left => '-25%')
border blue
para "Some left justified text\n", :align => 'left'
para "Some centred text\n", :align => 'center'
para "some right justified text\n", :align => 'right'
end
end


Related Topics



Leave a reply



Submit