Skip to content

Commit

Permalink
Completed simple conversion. Added (hopefully) helpful README
Browse files Browse the repository at this point in the history
  • Loading branch information
ddubyah committed Jun 6, 2011
1 parent 17cfddb commit 5fd66a9
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 44 deletions.
18 changes: 18 additions & 0 deletions Guardfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme

guard 'rspec', :version => 2 do
watch(%r{^spec/.+_spec\.rb})
watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }

# # Rails example
# watch('spec/spec_helper.rb') { "spec" }
# watch('config/routes.rb') { "spec/routing" }
# watch('app/controllers/application_controller.rb') { "spec/controllers" }
# watch(%r{^spec/.+_spec\.rb})
# watch(%r{^app/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
# watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
# watch(%r{^app/controllers/(.+)_(controller)\.rb}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }

end
4 changes: 2 additions & 2 deletions guard-markdown.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ Gem::Specification.new do |s|

s.rubyforge_project = "guard-markdown"

# s.files = `git ls-files`.split("\n")
s.files = Dir.glob('{lib}/**/*')
s.files = `git ls-files`.split("\n")
# s.files = Dir.glob('{lib}/**/*')
#s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
#s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]
Expand Down
37 changes: 24 additions & 13 deletions lib/guard/markdown.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,43 @@ class Markdown < Guard
# Your code goes here...
def initialize(watchers=[], options={})
super
# init stuff here, thx!
end
@options = {
:convert_on_start => true,
:dry_run => false
}.update(options)
end

def start
UI.info("Guard::Markdown has started watching your files")
run_all if @options[:convert_on_start]
end

def run_all
files = Dir.glob("**/*.*")
targets = Watcher.match_files(self, files)
#puts "Running changes on these paths: #{targets}"
targets = Watcher.match_files(self, files)
run_on_change targets
end

# Called on file(s) modifications
# TODO - this method does far too much. Must refactor to allow
# - for better testing
def run_on_change(paths)
paths.each do |path|
input, output = path.split("|")
puts "#{input} >> #{output}"
source = File.open(input,"rb").read
UI.info "#{input} >> #{output}"
unless @options[:dry_run]
source = File.open(input,"rb").read

# make sure directory path exists
reg = /(.+\/).+\.\w+/i
target_path = output.gsub(reg,"\\1")
FileUtils.mkpath target_path unless target_path.empty?
# make sure directory path exists
reg = /(.+\/).+\.\w+/i
target_path = output.gsub(reg,"\\1")
FileUtils.mkpath target_path unless target_path.empty?

doc = Kramdown::Document.new(source, :input => "markdown").to_html
doc = Kramdown::Document.new(source, :input => "markdown").to_html

File.open(output, "w") do |f|
f.puts(doc)
File.open(output, "w") do |f|
f.puts(doc)
end
end
end
true
Expand Down
10 changes: 3 additions & 7 deletions lib/guard/markdown/templates/Guardfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
guard 'markdown' do
# must produce a string => "input/path/file.md|target/path/output/file.html"
# The first regexp, watch (regexp) is used to match the files to be watched for changes
# The second regexp is used to determine the input path of the changed file, and the desired output path
# of the converted file, both built by the regexp matched against the detected changed file.
# The goal is to create a string of the form "input/path/file.md|output/path/file.html",
# i.e, both the input file path and the output file path separated by a pipe.
guard 'markdown', :convert_on_start => true, :dry_run => true do
# See README for info on the watch statement below
# Will not convert while :dry_run is true. Once you're happy with your watch statements remove it
watch (/source_dir\/(.+\/)*(.+\.)(md|markdown)/i) { |m| "source_dir/#{m[1]}#{m[2]}#{m[3]}|output_dir/#{m[1]}#{m[2]}html"}
end
64 changes: 64 additions & 0 deletions lib/guard/markdown/templates/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Guard::Markdown #
Markdown guard will watch your markdown documents for changes and convert them to lovely, semantic html. Yay!

## Install ##

You're going to need [Guard](https://github.com/guard/guard) too.

Install with

$ gem install guard-markdown

Or add it to your Gemfile

gem 'guard-markdown'

## Usage ##

Go see the [Guard usage doc](https://github.com/guard/guard#readme) for general instructions

## The Guardfile - where the magic happens

The Guardfile is where you define your desired input and output paths.
Create it with:

$ guard init markdown

Then tweak the watch statements to your hearts content. It'll look a lot like this:

guard 'markdown', :convert_on_start => true, :dry_run => true do
watch (/source_dir\/(.+\/)*(.+\.)(md|markdown)/i) { |m| "source_dir/#{m[1]}#{m[2]}#{m[3]}|output_dir/#{m[1]}#{m[2]}html"}
end

The guard statement defines which guard your configuring and sets any optional parameters.

* :convert_on_start - if true will run all conversions when you start the guard. Defaults to true
* :dry_run - if true won't actually run the conversion process, but it will output the files being watched and the file it would write to. Use it to tweak your watch statements and when you're happy set it to false.

The watch statement - ok, it may look a little intimidating. You'll need to know your regular expressions. But this is what it's doing.

watch (/source_dir\/(.+\/)*(.+\.)(md|markdown)/i) { |m| "source_dir/#{m[1]}#{m[2]}#{m[3]}|output_dir/#{m[1]}#{m[2]}html"}
^ ------ input file pattern ----------- ^ ^ ---- input file path -------- ^|^ ----- output file path ---^

The "input file pattern" is a regular expression that is used to determine which files are watched by the guard. It'll be applied recursively to all files and folders starting in the current working directory.

Any matches are passed into the block and used to construct the conversion command. The conversion command is a string containing the path to the source file and the desired path to the output file separated by a "|"

I hope that makes sense :)



## Have Fun ##

Go see the other [great guards available](https://github.com/guard/guard/wiki/List-of-available-Guards)

Oh yeah, I'm using [Kramdown](http://kramdown.rubyforge.org/) for the conversion engine. So if you want to know what markdown syntax it supports, [go here](http://kramdown.rubyforge.org/syntax.html)

# TODO #

* Simplify the required watch statement
* Seems a little wasteful to have to recreate the input path in the regexp. Must find a way around it.
* Allow the passing of Kramdown options into the guard
* Allow the conversion of more doc types using Kramdown

2 changes: 1 addition & 1 deletion lib/guard/markdown/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Guard
module MarkdownVersion
VERSION = "0.0.3"
VERSION = "0.1.0"
end
end
94 changes: 73 additions & 21 deletions spec/lib/guard/markdown_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'spec_helper'
require 'Kramdown'
require "guard/watcher"
require "guard/watcher"
require "guard/ui"

describe "Guard-Markdown" do

Expand All @@ -12,6 +13,41 @@
@input_paths.each_index do |i|
@changed_paths << "#{@input_paths[i]}|#{@output_paths[i]}"
end
end

describe "initialize" do
it "should start with default options" do
@subject.options[:convert_on_start].should be true
@subject.options[:dry_run].should be false
end

it "should be possible to overwrite the default options" do
@subject = Guard::Markdown.new([],{
:convert_on_start => false,
:dry_run => true })
@subject.options[:convert_on_start].should be false
@subject.options[:dry_run].should be true
end
end

describe "start" do
it "should show a welcome message" do
Guard::UI.should_receive(:info).with("Guard::Markdown has started watching your files")
@subject.start
end

describe "convert_on_start" do
it "should run all conversions if convert_on_start is true" do
@subject.should_receive(:run_all)
@subject.start
end
it "should not convert on start if convert_on_start is false" do
@subject = Guard::Markdown.new([],{ :convert_on_start => false })
@subject.should_not_receive(:run_all)
@subject.start
end
end

end

describe "run_on_change" do
Expand All @@ -23,37 +59,53 @@
File.should_receive(:open).with(@input_paths[i],"rb").and_return(file_double)

mock_kramdown("#Title").should_receive(:to_html).and_return("<h1>Title</h1>")

#test info messages
Guard::UI.should_receive(:info).with("#{@input_paths[i]} >> #{@output_paths[i]}")

#mock file write
file_out = double()
file_out = double()
target_path = @output_paths[i].gsub(/(.+\/).+\.\w+/i,"\\1")
FileUtils.should_receive(:mkpath).with(target_path)
File.should_receive(:open).with(@output_paths[i], "w").and_return(file_out)

#TODO Not sure how to test actually writing to the file

end
@subject.run_on_change(@changed_paths)
end

describe "dry run" do
it "should not permorm a conversion on a dry run" do
@subject = Guard::Markdown.new([],{ :dry_run=> true })
FileUtils.should_not_receive(:mkpath)
File.should_not_receive(:open)
Kramdown::Document.should_not_receive(:new)
Guard::UI.should_receive(:info).exactly(3).times
@subject.run_on_change(@changed_paths)
end
end
end

# describe "run_all" do
# it "should call run_on_change for all matching paths" do
# #mock Guard.watcher
# mock_watch = double()
#
# #mock Dir
# Dir.should_receive(:glob).with("**/*.*").and_return(@input_paths)
#
# subject = Guard::Markdown.new(mock_watch)
#
# #Guard::Watcher should handle the matching and path manipulation
# ## TODO the following line throws an uninitilizd const error Guard::Guard::Watcher -> don't know why. It'll have to go untested for now
# Watcher.should_receive(:match_files).with(subject, mock_watch).and_return(@changed_paths)
#
# subject.should_receive(:run_on_change).with(@changed_paths)
#
# subject.run_all
# end
# end
describe "run_all" do
it "should call run_on_change for all matching paths" do
#mock Guard.watcher
mock_watch = double()

#mock Dir
Dir.should_receive(:glob).with("**/*.*").and_return(@input_paths)

subject = Guard::Markdown.new(mock_watch)

#Guard::Watcher should handle the matching and path manipulation
## TODO the following line throws an uninitilizd const error Guard::Guard::Watcher -> don't know why. It'll have to go untested for now
Guard::Watcher.should_receive(:match_files).with(subject, @input_paths).and_return(@changed_paths)

subject.should_receive(:run_on_change).with(@changed_paths)

subject.run_all
end
end
end

private
Expand Down

0 comments on commit 5fd66a9

Please sign in to comment.