Skip to content
This repository was archived by the owner on Dec 24, 2019. It is now read-only.

Commit 40054c2

Browse files
committed
v0.10.0 - Lazy dep parameters, a major new feature.
One weakness of babushka's DSL has always been that deps aren't parameterised. There were a couple of existing ways to pass information between deps, the most obvious by using vars: dep 'rack app' do set :vhost_type, 'unicorn' requires 'vhost configured' end dep 'vhost configured' do met? { conf_exists?(var(:vhost_type)) } end This is problematic, because setting state and then triggering a process that separately makes use of that state is bad design. It's much better to pass the state around directly, because: - the data is much more localised: local arguments can only be read and written when they're in scope - it's more explicit, and hence more discoverable I attempted this previously by adding block arguments to deps. Up until today, it was possible to do this: dep 'rack app' do requires Dep('vhost configured').with('unicorn') end dep 'vhost configured' do |vhost_type| met? { conf_exists?(vhost_type) } end At first, this seemed like a great idea, but it turned out to be a flawed design. Firstly, local variables aren't accessible from within methods, so helper methods defined within deps couldn't access the args like met?{} and meet{} blocks could. But more problematically, local variables are a language-level feature in ruby, and so there's no control over how they behave - their names can't be discovered (on ruby 1.8), and they can't be lazily evaluated later; their values have to be present at the time the outer dep block is defined. The new design does away with block arguments, and uses a different notation to define dep parameters: dep 'vhost configured', :vhost_type do met? { conf_exists?(vhost_type) } end Each argument listed is defined on the dep as an instance method. That method returns a Parameter object which represents the value. You can pass the values either positionally, or by name (as a hash), when you require the dep... dep 'rack app' do # also, you can pass them directly to the string now requires 'vhost configured'.with('unicorn') # positional arguments end dep 'rack app' do requires 'vhost configured'.with(vhost_type: 'unicorn') # named arguments end ... And the values will be made available as methods on the dep, accessible anywhere within that dep's context. The idea of the Parameter object, though, is that it provides a lazy wrapper around the value. If you don't pass a value for a given parameter, the Parameter object that its method exposes will request the value from the prompt as required (i.e. when something like #to_s is called on it). When you pass the arguments positionally, like standard ruby arguments, the arity has to match: requiring the dep will fail otherwise, complaining that you didn't pass enough args. When you pass by name, though, you can include as many or as few of the dep's args as you like - the rest will be lazily requested from the prompt if and when the values they represent are accessed. Unlike vars, though, dep arguments are local to each dep - you have to explicitly pass them onwards for them to propagate. This seems like overhead, but I'm confident anyone who's written more than a handful of deps will agree that the alternative, shared vars, is not manageable over time. (And it turns out passing args around really isn't much of an overhead at all; it just involves being explicit about data requirements that were already there.) All the settings for vars are present with parameters, too, like defaults and choices. But unlike vars, which accept them as an options hash, parameters expose them as chainable methods. dep 'app bundled', :path, :env do path.default('.') env.ask('Which environment should be bundled?').default('production') # ... end I'm hoping that as they evolve, lazy dep parameters can mostly replace vars. Try them out - find your messiest dep; chances are it's that way because of a var-related workaround you had to make. Try converting it to use dep parameters instead, and you'll find that a lot of setup{} blocks, calls to #set & #default, and other similar noise, become unnecessary, because you can just directly pass state around and not worry about unintended interactions between shared state that vars inevitably cause. Feedback is super welcome, as it always is, to @babushka_app or http://babushka.me/mailing_list. Bugreports are much appreciated - http://github.com/benhoskings/babushka/issues. Share and enjoy! <3 -- Ben
1 parent 6a5c3a2 commit 40054c2

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

lib/babushka.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module Babushka
2-
VERSION = '0.9.8'
2+
VERSION = '0.10.0'
33
WorkingPrefix = '~/.babushka'
44
SourcePrefix = '~/.babushka/sources'
55
BuildPrefix = '~/.babushka/build'

0 commit comments

Comments
 (0)