Skip to content

willb/quiescent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

quiescent

This is a very simple mixin to support quiescing constants, which we call "quiescents" in Ruby. You may assign a value to a quiescing constant once during the execution of the program; however, a quiescing constant's value is fixed after the first time it is read. Quiescing constants may have default values (specified either as explicit values or argumentless blocks to compute that value) that take effect if they are not explicitly assigned to before their first use.

If you like the convenience of constants but might need to defer giving them values, you'll like quiescents. If you like single-assignment variables in languages like Prolog, you'll like quiescents. If you suspect that write-once values are far more common than most people admit, you'll like quiescents.

Here's a simple example:

require 'quiescent'

class Foo
  include Quiescent
  
  # This declares a constant named PostCode that 
  # quiesces to a default value of 53706 unless 
  # another is provided before the first time it
  # is read
  quiescent :PostCode, 53706
  
  # Let's assume that the awesome features are off
  # by default.
  quiescent :EnableTotallyAwesomeFeature, false
  quiescent :EnableSlightlyLessAwesomeFeature, false
  
  # This declares a constant named LazyThrees that 
  # quiesces to a list of all natural numbers less than
  # 100 that are divisible by three, as calculated
  # in the block, unless another value is provided. 
  # The block argument will execute at most once.
  quiescent :LazyThrees do
    (1..100).to_a.select {|x| x % 3 == 0}
  end
  
  # In this method, we'll see how to force quiescents
  # to quiesce by giving them values and reading their
  # values.
  def self.setup
    # We only want to do this once
    return if @setup_done
    @setup_done = true
    
    puts "The postal code is #{Foo::PostCode}"
    
    # You can provide non-default values with the
    # quiesce method...
    Foo.quiesce(:EnableTotallyAwesomeFeature, "sometimes")
    
    # ...or by using a special CONSTNAME= method, which
    # will be intercepted by method_missing.
    Foo.EnableSlightlyLessAwesomeFeature = true
    
    # Note that this only works for names corresponding
    # to declared quiescing constants...
    begin
      Foo.EnableCrummyFeature = true 
    rescue Exception
      puts("whoa, failure in aisle 47")
    end

    # ...and only once for each quiescing constant.
    begin
      Foo.EnableSlightlyLessAwesomeFeature = false
    rescue Exception
      puts("nice try, pal")
    end
  end
end

Potential gotchas

Because of how constant resolution works in Ruby, we don't have a way to support quiescents whose names are identical to constants declared in the global namespace. If you try and declare one, for example, Foo::Kernel, you'll get the toplevel Kernel when you try to access Foo::Kernel, along with the following message:

warning: toplevel constant Kernel referenced by Foo::Kernel

Quiescent adds const_missing and method_missing methods to classes that mix it in. These should play nicely with preexisting implementations of these (although these interactions are not exhaustively tested); however, classes that provide their own implementations of these methods should do so with care. Please report any problematic interactions with your own code.

Contributing to quiescent

  • Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
  • Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
  • Fork the project
  • Start a feature/bugfix branch
  • Commit and push until you are happy with your contribution
  • Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
  • Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

Copyright

Copyright (c) 2011 Red Hat, Inc. See LICENSE.txt for further details.

About

Defaultable, single-assignment constants for Ruby

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages