compass/test/command_line_helper.rb
Chris Eppstein f59ca512ce Refactor of the internal datastructures used to access project
configuration. Configuration is now a singly linked list of configuration objects
that inherit values and defaults from the next configuration instance.
All instances hold a reference to the top of the configuration chain.

There is now a consistent API for reading configuration property values:

                <attr>: Reads the fully-resolved attribute after taking
                        configuration inheritance and defaults into account.
            raw_<attr>: reads attribute from a configuration object without
                        inheritance or defaults.
   default_for(<attr>): reads the default value for an attribute
    default_for_<attr>: specifies the default value for an attribute.
<attr>_without_default: reads the inherited attribute without applying defaults.
    comment_for_<attr>: Specifies a comment that will be emitted above the
                        property when serializing the configuration to a file.

Additionally, method_missing and respond_to both work down the
configuration chain, so any method that is added to a configuration
instance, can be accessed from the top level.

The distinction between default and explicitly set values allows compass
to more correctly manage the serialization of attributes when creating
configuration files for projects.

The compass configuration can still be accessed via
Compass.configuration, however, the configuration object is no longer a
singleton. This means that you can build several configuration chains
to track several projects at once. This should ease the use of compass
in other frameworks and plugins that want to use compass internally.
2009-08-29 13:20:32 -07:00

94 lines
2.5 KiB
Ruby

module Compass::CommandLineHelper
def compass(*arguments)
options = arguments.last.is_a?(Hash) ? arguments.pop : {}
options[:wait] = 0.25
if block_given?
responder = Responder.new
yield responder
IO.popen("-", "w+") do |io|
if io
#parent process
output = ""
eof_at = nil
while !eof_at || (Time.now - eof_at < options[:wait])
if io.eof?
eof_at ||= Time.now
sleep 0.1
else
eof_at = nil
timeout(1) do
output << io.readpartial(1024)
end
prompt = output.split("\n").last
if response = responder.response_for(prompt)
io.puts response
end
end
end
responder.assert_required_responses!
@last_result = output
else
#child process
execute *arguments
end
end
else
@last_result = capture_output do
execute *arguments
end
end
rescue Timeout::Error
fail "Read from child process timed out"
end
class Responder
Response = Struct.new(:prompt, :text, :required, :responded)
def initialize
@responses = []
end
def respond_to(prompt, options = {})
@responses << Response.new(prompt, options[:with], options[:required])
end
def response_for(prompt)
response = @responses.detect{|r| r.prompt == prompt}
if response
response.responded = true
response.text
end
end
def assert_required_responses!
@responses.each do |response|
if response.required && !response.responded
raise "Prompt not encountered: \"#{response.prompt}\""
end
end
end
end
def assert_action_performed(action, path)
actions_found = []
@last_result.split("\n").each do |line|
line = line.split
return if line.first == action.to_s && line.last == path
actions_found << line.first if line.last == path
end
message = "Action #{action.inspect} was not performed on: #{path}."
message += "The following actions were performed: #{actions_found.join(", ")}" if actions_found.any?
puts @last_result
fail message
end
def within_tmp_directory(dir = "tmp")
d = absolutize(dir)
FileUtils.mkdir_p(d)
Dir.chdir(d) do
yield
end
ensure
FileUtils.rm_rf(d)
end
def execute(*arguments)
Compass::Exec::Compass.new(arguments).run!
end
end