Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Adding a Writer object.

  • Loading branch information...
commit 1b793cb75e7ae9acc0aaa009b0f4c6f16597e047 1 parent 3e04751
James Edward Gray II authored
4 .gitignore
View
@@ -1 +1,3 @@
-doc
+.DS_Store
+**/.DS_Store
+doc
6 lib/mungr/staged.rb
View
@@ -74,13 +74,13 @@ def finish(&code)
#
# Provides the dual code setting and running behavior of all stage methods.
# If +code+ is non-+nil+ it will be passed on to load_code(), otherwise
- # +name+ code will be run.
+ # +name+ code will be run. Any +args+ will be forwarded to the run method.
#
- def load_or_run(name, &code)
+ def load_or_run(name, *args, &code)
if code
load_code(name, code)
else
- send("run_#{name}_code")
+ send("run_#{name}_code", *args)
end
end
75 lib/mungr/writer.rb
View
@@ -0,0 +1,75 @@
+# encoding: UTF-8
+
+require "mungr/staged"
+
+module Mungr
+ #
+ # Objects of this class are the basic unit of output for Mungr scripts.
+ # Writing using one of these objects is a four stage process:
+ #
+ # 1. A Writer is built and configured
+ # 2. The Writer is prepared just before the first write
+ # 3. Chunks of data are written to the Writer one by one
+ # 4. A final call is made to finish the Writer
+ #
+ class Writer < Staged
+ #
+ # Use the +init+ block to build a Writer by assigning code to each of the
+ # three code stages, something like:
+ #
+ # file_writer = Writer.new do |w|
+ # w.prepare { File.open("my_file.txt", "w") }
+ # w.write { |f, line| f.puts line }
+ # w.finish { |f| f.close }
+ # end
+ #
+ # The prepare() and finish() stages are optional.
+ #
+ # Once built, you feed data you wish to output into the write() method and
+ # then call finish() when you are done, like this:
+ #
+ # file_writer.write("some data")
+ # file_writer.write("more data")
+ # # ...
+ # file_writer.finish # signal that we are done writing
+ #
+ def initialize(*args, &init)
+ @write_code = nil
+
+ super
+ end
+
+ #
+ # :call-seq:
+ # write() { |context| code_to_read_one_chunk_of_data() }
+ # write(*output)
+ #
+ # If passed a block, this method sets the code that will be used to write a
+ # single chunk of output. The block will also be passed the context
+ # returned from prepare().
+ #
+ # This method, called without block, is also the primary writing interface.
+ # You can just call it repeatedly to output values.
+ #
+ def write(*output, &code)
+ load_or_run(:write, *output, &code)
+ end
+
+ #######
+ private
+ #######
+
+ #
+ # This method is the primary interface for writing. It will:
+ #
+ # * Return +nil+ if finished?() is now +true+
+ # * Run prepare() unless prepared?() is now +true+
+ # * Run the write code to output one chunk of data
+ #
+ def run_write_code(*args)
+ return if finished?
+ prepare unless prepared?
+ @write_code[@context, *args]
+ end
+ end
+end
8 test/test_reader.rb
View
@@ -45,14 +45,16 @@ def test_exhausting_a_reader_sets_finished
def test_any_value_returned_from_prepare_is_forwarded_to_read_and_finish
object = Object.new
+ calls = Array.new
reader do |r|
r.prepare { object }
r.read { |context|
- assert_same(object, context)
+ calls << context
nil # signal that we are exhausted
}
- r.finish { |context| assert_same(object, context) }
- end.read
+ r.finish { |context| calls << context }
+ end.read # trigger read and finish code
+ assert_equal([object] * 2, calls)
end
###############
78 test/test_writer.rb
View
@@ -0,0 +1,78 @@
+# encoding: UTF-8
+
+require "minitest/autorun"
+
+require "mungr/writer"
+
+class TestWriter < MiniTest::Unit::TestCase
+ ##############
+ ### Status ###
+ ##############
+
+ def test_a_writer_is_prepared_before_the_first_write
+ order = Array.new
+ writer do |w|
+ w.prepare { order << :prepared }
+ w.write { order << :write }
+ end
+ assert(!@writer.prepared?, "The Writer was prepared?() before the write().")
+ @writer.write("data")
+ assert( @writer.prepared?,
+ "The Writer was not prepared?() after the write()." )
+ assert_equal([:prepared, :write], order)
+ end
+
+ ###############
+ ### Context ###
+ ###############
+
+ def test_any_value_returned_from_prepare_is_forwarded_to_write_and_finish
+ object = Object.new
+ calls = Array.new
+ writer do |w|
+ w.prepare { object }
+ w.write { |context| calls << context }
+ w.finish { |context| calls << context }
+ end
+ @writer.write("data") # trigger write code
+ @writer.finish # trigger finish code
+ assert_equal([object] * 2, calls)
+ end
+
+ ###############
+ ### Writing ###
+ ###############
+
+ def test_calling_write_a_with_block_sets_the_code_and_further_calls_run_it
+ data = (1..3).to_a
+ written = Array.new
+ writer do |w|
+ w.write { |_, value| written << value }
+ end
+ data.each do |value|
+ @writer.write(value)
+ end
+ assert_equal(data, written)
+ end
+
+ def test_prepare_is_called_once_before_the_first_read
+ data = (1..3).to_a
+ calls = Array.new
+ writer do |w|
+ w.prepare { calls << :prepare }
+ w.write { |_, value| calls << value }
+ end
+ data.each do |value|
+ @writer.write(value)
+ end
+ assert_equal([:prepare] + data, calls)
+ end
+
+ #######
+ private
+ #######
+
+ def writer(&init)
+ @writer = Mungr::Writer.new(&init)
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.