On 9/7/05, Joe Van Dyk <joevandyk / gmail.com> wrote:
> On 8/18/05, Jacob Fugal <lukfugl / gmail.com> wrote:
> > > node :node1 do
> > >   ip 192.whatever
> > >   title "Node 1"
> > > end
> > >
> > > node :node2 do
> > >   ip 192.whatever
> > >   title "Node 2"
> > > end
> >
> > <snip>
> >
> > > class ClusterManager
> > >
> > >   def load_config_file config_file
> > >     instance_eval File.read(config_file)
> > >   end
> > >
> > >   def node node_id, &block
> > >     # What goes here?
> > >   end
> > >
> > > end
> >
> > I'd think similarly, but a bit different in that
> > ClusterManager::Builder should be the one doing the instance eval:
> >
> > class ClusterManager
> >   attr_accessor :nodes
> >
> >   def initialize
> >     @nodes = []
> >   end
> >
> >   def describe
> >     @nodes.collect{ |node| node.describe }.join("\n")
> >   end
> >
> >   class Node
> >     attr_accessor :id, :ip, :title
> >
> >     def initialize( id )
> >       @id = id
> >     end
> >
> >     def describe
> >       "#@id -> #@ip \"#@title\""
> >     end
> >
> >     class Builder
> >       def process( node, dsl )
> >         @node = node
> >         instance_eval &dsl
> >       end
> >
> >       def ip( value )
> >         @node.ip = value
> >       end
> >
> >       def title( value )
> >         @node.title = value
> >       end
> >     end
> >   end
> >
> >   class Builder
> >     def process( manager, dsl )
> >       @manager = manager
> >       @node_builder = Node::Builder.new
> >       instance_eval &dsl
> >     end
> >
> >     def node( node_id, &block )
> >       node = Node.new( node_id )
> >       @node_builder.process( node, block )
> >       @manager.nodes << node
> >     end
> >   end
> > end
> >
> > dsl = lambda{
> >   node :node1 do
> >     ip '192.whatever'
> >     title 'Node 1'
> >   end
> >
> >   node :node2 do
> >     ip '192.whatever'
> >     title 'Node 2'
> >   end
> > }
> >
> > manager = ClusterManager.new
> > builder = ClusterManager::Builder.new
> > builder.process( manager, dsl )
> >
> > puts manager.describe
> >
> > ###############
> >
> > A few caveats about the above:
> >
> > 1) You'll notice I changed the DSL a little (quoted the 192.whatever
> > values). That was simply for brevity in this illustration.
> >
> > 2) My Builders require the argument to process be lambdas (Procs) not
> > strings. This was because I didn't want to complicate things with
> > switches on whether to use the prefix & or not. But it would be as
> > simple as an if/else to hide the lambda/string distinction from the
> > "user" (which will be yourself, not the person writing in the DSL)
> > inside the Builder. Alternatively, you can take a string and build it
> > into a lambda for the Builder via eval("lambda{ #{dsl} }"). I wouldn't
> > necessarily recommend that though (with all the evils of eval).
> 
> Thank you for your ideas.  I've adapted it somewhat for parts of my
> application, but I'm running into problems.
> 
> I've got the following configuration file:
> 
> option :display do
>   display :text, :size => 20, :title => "DISPLAY"
>   value :DISPLAY, :default => ENV['DISPLAY'] || 'localhost:0'
> end
> 
> argument :xterm_title do
>   display :text, :size => 20, :title => "Xterm Title"
>   value "-T", :default => "You are on a xterm!"
> end
> 
> argument :xterm_text_color do
>   display :text, :size => 20, :title => "Xterm Font Color"
>   value "-fg", :default => "red"
> end
> 
> 
> application :xterm do
>   executable "/usr/X11R6/bin/xterm"
>   title     :Xterm
>   node      :fatire
>   options   :display
>   arguments :xterm_text_color, :xterm_title
> end
> 
> application :xeyes do
>   executable "/usr/X11R6/bin/xeyes"
>   title      :Xeyes
>   node       :fatire
>   options    :display
> end
> 
> 
> Should be self-explanatory.  I have some applications that take env
> options and command-line arguments, and I want to have a very readable
> and configurable file for defining those applications, options, and
> arguments (and some other things).  The 'node' option for the
> application is the machine that the application should be started on.
> The 'display' option for the options/arguments state how the GUI
> should display the option/argument.
> 
> My problem is trying to adapt your solution to fit something like
> this.  There would be a lot of duplication if I had Builders for
> applications, nodes, options, and arguments.  And I'm also having some
> difficulties getting each Application object to know what options and
> arguments it should have.
> 
> I considered using YAML for the configuration file format, but I'm
> still leaning towards having a pure Ruby file.
> 
> Thoughts are greatly appreciated!  This is my first time trying to do
> this type of programming, so it's a little weird.
> 


I would also like to be able to 'group' things together, like

group :xterm_options_arguments do
  arguments   :xterm_title, :xterm_text_color
  options :display
end

application :xterm do
  group :xterm_options_arguments
  title :Xterm
  ... 
end

So that applications with common options and arguments can specify a grouping.

(btw, an 'argument' is a command-line argument, like 'ls -F'... the -F
is an argument.  An option is something like "DISPLAY=my_machine:1
xeyes".. the DISPLAY is an option).