transfigr 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Daniel Neighman
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,102 @@
1
+ h1. Transfigr
2
+
3
+ A simple, pluggable plugin to transfigure an object into a format.
4
+ It can be used as a simple markup transfigurer, i.e. textile or markdown.
5
+ It can also be used as a general purpose presenter if you define it as such.
6
+
7
+ h2. Example
8
+
9
+ <pre><code>
10
+ Transfigr.format!(:textile, "h1. I am a textile string")
11
+ Transfigr.format!(:markdown, "I _am_ a markdown string")
12
+ </code></pre>
13
+
14
+ h3. Using options
15
+ You can configure your formatters to take an options hash to customize
16
+ the format based on options.
17
+
18
+ <pre><code>
19
+ Transfigr.add(:xml) do
20
+ def format!(opts)
21
+ target.to_xml(opts)
22
+ end
23
+ end
24
+
25
+ Transfigr.format!(:xml, @person_list, :fields => [:name, :age])
26
+ </code></pre>
27
+
28
+ This is especially useful when using it as a presenter in merb.
29
+
30
+ h2. Using it as a Presenter
31
+
32
+ <pre><code>
33
+ Transfigr.presenter(@article).to_xml # requires an :xml format be setup
34
+ </code></pre>
35
+
36
+ This is especially useful when using something like Merb's display method.
37
+
38
+ All _active_ formats have a method added to the presenter @to_<format>@
39
+
40
+ h3. Options in the presenter.
41
+
42
+ Sometimes you need to customize the format of an object based on
43
+ the current environment or state of the application.
44
+
45
+ Transfigr presenters allow options to be passed into the format! method.
46
+
47
+ As an example, in merb you may use:
48
+
49
+ <pre><code>
50
+ display Transfigr.presenter(@user, :fields => [:name, :age])
51
+ </code></pre>
52
+
53
+ When you define the formats, you can make use of any options passed it.
54
+
55
+ h2. Pluggable Back End
56
+
57
+ The architecture is pluggable so that you can add your own custom formatters.
58
+
59
+ By default there are currently:
60
+
61
+ * :textile - Via RedCloth (you need to install redcloth)
62
+ * :markdown - Via RDiscount or as a fallback Bluecloth. RDiscount is much faster http://tomayko.com/writings/ruby-markdown-libraries-real-cheap-for-you-two-for-price-of-one
63
+
64
+ h3. Make your own store
65
+
66
+ To define your own format is really simple. Lets look at the textile one.
67
+
68
+ <pre><code>
69
+ Transfigr.add(:textile)
70
+ after_activation do
71
+ require 'redcloth'
72
+ end
73
+
74
+ def format!(options = {})
75
+ RedCloth.new(target).to_html
76
+ end
77
+ end
78
+ end
79
+ </code></pre>
80
+
81
+ You can define any helpers inline. You can also @edit@ existing formats.
82
+ Replace formats by simply adding a new one with the same name.
83
+
84
+ The @after_activation@ block in the add methodis called when the formatter is activated.
85
+ It is a good place to put any dependencies the formatter may require.
86
+
87
+ The @format!(options = {})@ method is the work horse. This is the method that is called to actually transform
88
+ a string to the new format.
89
+
90
+ h3. Activation
91
+
92
+ You must activate a format in order to use it.
93
+ It is not secure to simply automatically load them.
94
+
95
+ You can activate existing formats like this:
96
+ <pre><code>
97
+ Transfigr.activate!(:textile, :markdown, :xml, :html, :pdf, :foo)
98
+ </code></pre>
99
+
100
+ You must have these formats defined. Check like @Transfigr.defined?(:foo)@
101
+
102
+ That's basically it.
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require "spec/rake/spectask"
4
+
5
+ GEM_NAME = "transfigr"
6
+ GEM_VERSION = "0.1.0"
7
+ AUTHOR = "Daniel Neighman"
8
+ EMAIL = "has.sox@gmail.com"
9
+ HOMEPAGE = "http://rubunity.com"
10
+ SUMMARY = "A Pluggable Markup Formatter"
11
+
12
+ spec = Gem::Specification.new do |s|
13
+ s.rubyforge_project = 'transfigr'
14
+ s.name = GEM_NAME
15
+ s.version = GEM_VERSION
16
+ s.platform = Gem::Platform::RUBY
17
+ s.has_rdoc = true
18
+ s.extra_rdoc_files = ["README.textile", "LICENSE", 'TODO']
19
+ s.summary = SUMMARY
20
+ s.description = s.summary
21
+ s.author = AUTHOR
22
+ s.email = EMAIL
23
+ s.homepage = HOMEPAGE
24
+ s.require_path = 'lib'
25
+ s.files = %w(LICENSE README.textile Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
26
+ end
27
+
28
+ Rake::GemPackageTask.new(spec) do |pkg|
29
+ pkg.gem_spec = spec
30
+ end
31
+
32
+ desc "Install the gem"
33
+ task :install => [:clobber_package, :package] do
34
+ system "gem install pkg/transfigr-#{GEM_VERSION}.gem"
35
+ end
36
+
37
+ desc "Run all specs"
38
+ Spec::Rake::SpecTask.new("spec") do |t|
39
+ t.spec_opts = ["--format", "specdoc", "--colour"]
40
+ t.spec_files = Dir["spec/**/*_spec.rb"].sort
41
+ t.rcov = false
42
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
43
+ t.rcov_opts << '--only-uncovered'
44
+ end
data/TODO ADDED
@@ -0,0 +1,5 @@
1
+ TODO:
2
+ Fix LICENSE with your name
3
+ Fix Rakefile with your name and contact info
4
+ Add your code to lib/transfigr.rb
5
+ Add your Merb rake tasks to lib/transfigr/merbtasks.rb
data/lib/transfigr.rb ADDED
@@ -0,0 +1,127 @@
1
+ require 'rubygems'
2
+
3
+ module Transfigr
4
+ class MissingFormatMethod < Exception; end
5
+ class FormatterNotFound < Exception; end
6
+
7
+ class << self
8
+ # Use the format method to format an object via a given formatter
9
+ # Normally this would be a string, but it could be anything.
10
+ #
11
+ # Example:
12
+ #
13
+ # Transfigr.format!(:textile, "h1. I'm a textile string")
14
+ #
15
+ # :api: public
16
+ def format!(format, object, opts = {})
17
+ raise "#{format.inspect} is not an active format" unless active?(format)
18
+ self[format].new(object).format!(opts)
19
+ end
20
+
21
+ # Activate formatters that you want to actually use. This
22
+ # allows formatters to be loaded, but not actually activated,
23
+ # leaving their dependencies behind. Activation can be done implicitly
24
+ # by just using a registered format.
25
+ #
26
+ # :api: public
27
+ def activate!(*args)
28
+ args.each do |f|
29
+ fmtr = formatters[f]
30
+ raise "No Formatter found for format #{f.inspect}" unless fmtr
31
+ _active_formats[f.to_s] = f
32
+ Presenter.add_format!(f)
33
+ fmtr.after_activation.call if fmtr.after_activation
34
+ true
35
+ end
36
+ end
37
+
38
+ # Deactivate and already active format
39
+ #
40
+ # :api: public
41
+ def deactivate!(*args)
42
+ args.each do |f|
43
+ _active_formats.delete(f.to_s)
44
+ Presenter.remove_format!(f)
45
+ end
46
+ end
47
+
48
+ # Allows you to add a formatter. A formatter should
49
+ # At minimum define a format!(opts={}) method.
50
+ # I there is no format! method Transfigr::MissingFormatMethod will be raised
51
+ #
52
+ # Example
53
+ #
54
+ # Transfigr.add(:foo) do
55
+ # def format!(opts = {})
56
+ # "<foo>#{target}</foo>"
57
+ # end
58
+ # end
59
+ #
60
+ # :api: public
61
+ def add(name, &block)
62
+ formatter = Class.new(Formatter, &block)
63
+ raise MissingFormatMethod unless formatter.instance_methods.include?("format!")
64
+ self.formatters[name] = formatter
65
+ end
66
+
67
+ # Provides acces to edit the formatter. It's the same as getting another crack
68
+ # at the add block
69
+ #
70
+ # Example
71
+ #
72
+ # Transfigr.edit(:foo){ def my_helper; "bar"; end }
73
+ #
74
+ # :api: public
75
+ def edit(name, &block)
76
+ fmtr = formatters[name]
77
+ raise FormatterNotFound unless fmtr
78
+ fmtr.class_eval(&block)
79
+ end
80
+
81
+ # Provides a list of currently active formats
82
+ # :api: public
83
+ def active_formats
84
+ _active_formats.keys.sort
85
+ end
86
+
87
+ # Check to see if a format has been activated
88
+ # :api: public
89
+ def active?(format)
90
+ !!_active_formats[format.to_s]
91
+ end
92
+
93
+ # Checks to see if a formatter has been defined
94
+ # :api: public
95
+ def defined?(format)
96
+ formatters.keys.include?(format)
97
+ end
98
+
99
+ protected
100
+ # provides a list of declared formatters
101
+ # :api: private
102
+ def formatters
103
+ @formatters ||= {}
104
+ end
105
+
106
+ private
107
+ # Provides access to the formatter
108
+ # :api: private
109
+ def [](formatter)
110
+ formatters[_active_formats[formatter.to_s]]
111
+ end
112
+
113
+ # A hash of active formats with the format_as as the key, and the class as the value
114
+ # :api: private
115
+ def _active_formats
116
+ @_active_formats ||= {}
117
+ end
118
+
119
+
120
+ end # self
121
+ end # Transfigr
122
+
123
+ $:.unshift File.dirname(__FILE__)
124
+ require 'transfigr/presenter'
125
+ require 'transfigr/abstract_formatter'
126
+ require 'transfigr/formatters/markdown'
127
+ require 'transfigr/formatters/textile'
@@ -0,0 +1,27 @@
1
+ module Transfigr
2
+ # Transfigr::Formatter is the base class to inherit from when developing your own formatters
3
+ class Formatter
4
+ attr_accessor :target
5
+
6
+ def initialize(target)
7
+ @target = target
8
+ end
9
+
10
+ # The after_activation block allows you to call code after the formatter has been activated.
11
+ # This includes requireing any dependencies
12
+ #
13
+ # Example
14
+ #
15
+ # class MyFoo < Transfigr::Formatter
16
+ # # snip
17
+ # after_activation{ require "foo" }
18
+ # #snip
19
+ # end
20
+ #
21
+ # :api: plugin
22
+ def self.after_activation(&block)
23
+ @after_activation = block if block_given?
24
+ @after_activation
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ Transfigr.add(:markdown) do
2
+ after_activation do
3
+ begin
4
+ require 'rdiscount'
5
+ BlueCloth = RDiscount
6
+ rescue LoadError
7
+ require 'bluecloth'
8
+ end
9
+ end
10
+
11
+ def format!(opts = {})
12
+ BlueCloth.new(target).to_html
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ Transfigr.add(:textile) do
2
+ after_activation do
3
+ require 'redcloth'
4
+ end
5
+
6
+ def format!(opts = {})
7
+ RedCloth.new(target).to_html
8
+ end
9
+ end
@@ -0,0 +1,58 @@
1
+ module Transfigr
2
+
3
+ # Use this as a presenter object to access the object by a to_<format> method.
4
+ # This is useful when using something like Merb's display method.
5
+ # It stronly defines presentation logic elsewhere from the object
6
+ #
7
+ # Example
8
+ #
9
+ # display Transfigr.presenter(@article)
10
+ #
11
+ # Tranfigr.presenter(@article).to_textile
12
+ #
13
+ # :api: public
14
+ def self.presenter(object, opts = {})
15
+ Presenter.new(object, opts)
16
+ end
17
+
18
+ # :api: private
19
+ class Presenter
20
+ attr_reader :target, :options
21
+
22
+ def initialize(target, options = {})
23
+ @target, @options = target, options
24
+ end
25
+
26
+ # Need to undefine all the to_xxx methods
27
+ to_methods = self.instance_methods.grep(/^to_/)
28
+ to_methods.each do |meth|
29
+ undef_method meth.to_sym unless meth == "to_s" || meth == "to_string"
30
+ end
31
+
32
+ # Adds a formatter to the presenter
33
+ # :api: private
34
+ def self.add_format!(format)
35
+ self.class_eval <<-RUBY
36
+ def to_#{format}
37
+ Transfigr.format!(:#{format}, target, options)
38
+ end
39
+ RUBY
40
+ end
41
+
42
+ # Removes the formatter method from the presenter
43
+ # :api: private
44
+ def self.remove_format!(format)
45
+ undef_method :"to_#{format}"
46
+ end
47
+
48
+ # :api: overwritable
49
+ def method_missing(name, *rest)
50
+ if name.to_s =~ /^to_/
51
+ return target.send(name) if target.respond_to?(name)
52
+ raise FormatterNotFound, "No active #{name.inspect} format was found"
53
+ end
54
+ super
55
+ end
56
+
57
+ end # Presenter
58
+ end # Transfigr
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "markdown formatting" do
4
+ before(:all) do
5
+ Transfigr.activate!(:markdown)
6
+ end
7
+ it "should render a textile string as html" do
8
+ Transfigr.format!(:markdown, "I'm biched _es_").should match(/^<p>I'm biched <em>es<\/em><\/p>/)
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "textile formatting" do
4
+ before(:all) do
5
+ Transfigr.activate!(:textile)
6
+ end
7
+ it "should render a textile string as html" do
8
+ Transfigr.format!(:textile, "h1. Foo Dude").should == "<h1>Foo Dude</h1>"
9
+ end
10
+ end
@@ -0,0 +1,39 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "Transfigr.presenter(obj)" do
4
+
5
+ before(:each) do
6
+ Transfigr.add(:active_presenter_format) do
7
+ def format!(o)
8
+ :presenter_format_formatted
9
+ end
10
+ end
11
+ Transfigr.activate!(:active_presenter_format)
12
+ end
13
+
14
+ it "should setup a presenter" do
15
+ Transfigr.presenter(Object.new).should be_an_instance_of(Transfigr::Presenter)
16
+ end
17
+
18
+ it "should allow me to call me to call a format via to_<format> on an activated format" do
19
+
20
+ Transfigr.presenter(Object.new).to_active_presenter_format.should == :presenter_format_formatted
21
+ end
22
+
23
+ it "should raise a FormatterNotFound when calling to_<unknown_format>" do
24
+ Transfigr.should_not be_defined(:not_defined)
25
+ lambda do
26
+ Transfigr.presenter(Object.new).to_not_defined
27
+ end.should raise_error(Transfigr::FormatterNotFound)
28
+ end
29
+
30
+ it "should fall back to the objects to_xxx method if there is no format one found" do
31
+ class PresenterFoo
32
+ def to_xxx
33
+ :fallback
34
+ end
35
+ end
36
+ Transfigr.presenter(PresenterFoo.new).to_xxx.should == :fallback
37
+ end
38
+
39
+ end
@@ -0,0 +1,2 @@
1
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'transfigr'
@@ -0,0 +1,119 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "transfigr" do
4
+ before(:each){$captures = []}
5
+
6
+ it "should allow a developer to activate a formatter" do
7
+ Transfigr.add(:foo1){ def format!(opts={}); end }
8
+ Transfigr.activate!(:foo1)
9
+ Transfigr.active?(:foo1).should be_true
10
+ end
11
+
12
+ it "should allow activation of multiple formatters" do
13
+ Transfigr.add(:foo2){ def format!(opts={}); end }
14
+ Transfigr.add(:foo3){ def format!(opts={}); end }
15
+ Transfigr.activate!(:foo2, :foo3)
16
+ [:foo2, :foo3].each do |foo|
17
+ Transfigr.active?(foo).should be_true
18
+ end
19
+ end
20
+
21
+ it "should raise and exception if there is no format! method defined" do
22
+ lambda do
23
+ Transfigr.add(:no_format_foo){ }
24
+ end.should raise_error(Transfigr::MissingFormatMethod)
25
+ end
26
+
27
+ it "should not define a format! method on the base class" do
28
+ Transfigr::Formatter.instance_methods.should_not include("format!")
29
+ end
30
+
31
+ it "should not be activated for a formatter that has not been activate" do
32
+ Transfigr.add(:foo4){ def format!(opts={}); end }
33
+ Transfigr.active?(:foo4).should be_false
34
+ end
35
+
36
+ it "should allow the formatter to run after_activation code" do
37
+ Transfigr.add(:foo5) do
38
+ after_activation { $captures << :foo5 }
39
+ def format!(opts={}); end
40
+ end
41
+ Transfigr.activate!(:foo5)
42
+ $captures.should == [:foo5]
43
+ end
44
+
45
+ it "should not run the after_Activation code if the formatter has not been activated" do
46
+ Transfigr.add(:foo6) do
47
+ after_activation{ $captuers << :foo6 }
48
+ def format!(opts={}); end
49
+ end
50
+ $captures.should_not include(:foo6)
51
+ end
52
+
53
+ it "should format a string with the provided fromatter" do
54
+ Transfigr.add(:foo8) do
55
+ def format!(opts = {})
56
+ ":foo8 - #{target}"
57
+ end
58
+ end
59
+ Transfigr.activate!(:foo8)
60
+ Transfigr.format!(:foo8, "foobar").should == ":foo8 - foobar"
61
+ Transfigr.format!("foo8", "bazbar").should == ":foo8 - bazbar"
62
+ end
63
+
64
+ it "should allow for options to be passed to the format" do
65
+ Transfigr.add(:foo9) do
66
+ def format!(opts = {})
67
+ ":foo9 - #{target} - #{opts.inspect}"
68
+ end
69
+ end
70
+ Transfigr.activate!(:foo9)
71
+ Transfigr.format!(:foo9, "string", :foo => :bar).should == ":foo9 - string - {:foo=>:bar}"
72
+ end
73
+
74
+ it "should allow me to edit a formatter" do
75
+ Transfigr.add(:foo10){ def format!(o={}); $captures << :original; end }
76
+ Transfigr.activate!(:foo10)
77
+ Transfigr.format!(:foo10, :foo)
78
+ Transfigr.edit(:foo10){ def format!(o={}); $captures << :modified; end}
79
+ Transfigr.format!(:foo10, :foo)
80
+ $captures.should == [:original, :modified]
81
+ end
82
+
83
+ it "should raise an exception if a formatter is edited that does not exist" do
84
+ lambda do
85
+ Transfigr.edit(:will_never_exist){ def format!(o); "foo"; end }
86
+ end.should raise_error(Transfigr::FormatterNotFound)
87
+ end
88
+
89
+ it "should allow me to replace a formatter" do
90
+ Transfigr.add(:foo11) do
91
+ def helper; :helper; end
92
+ def format!(o); $captures << :noooo; end
93
+ end
94
+ Transfigr.activate!(:foo11)
95
+ Transfigr.add(:foo11) do
96
+ def format!(o)
97
+ $captures << :yeeees
98
+ $captures << self.respond_to?(:helper)
99
+ end
100
+ end
101
+
102
+ Transfigr.format!(:foo11, "")
103
+ $captures.should == [:yeeees, false]
104
+ end
105
+
106
+ it "should allow you to deactivate a format" do
107
+ Transfigr.add(:foo12){ def format!(o); :foo12; end }
108
+ Transfigr.activate!(:foo12)
109
+ Transfigr.should be_active(:foo12)
110
+ Transfigr.deactivate!(:foo12)
111
+ Transfigr.should_not be_active(:foo12)
112
+ end
113
+
114
+ it "should tell you if a formatter has been defined" do
115
+ Transfigr.should_not be_defined(:to_be_defined)
116
+ Transfigr.add(:to_be_defined){ def format!(o); :foo; end }
117
+ Transfigr.should be_defined(:to_be_defined)
118
+ end
119
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: transfigr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Neighman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-10 00:00:00 +11:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A Pluggable Markup Formatter
17
+ email: has.sox@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.textile
24
+ - LICENSE
25
+ - TODO
26
+ files:
27
+ - LICENSE
28
+ - README.textile
29
+ - Rakefile
30
+ - TODO
31
+ - lib/transfigr
32
+ - lib/transfigr/abstract_formatter.rb
33
+ - lib/transfigr/formatters
34
+ - lib/transfigr/formatters/markdown.rb
35
+ - lib/transfigr/formatters/textile.rb
36
+ - lib/transfigr/presenter.rb
37
+ - lib/transfigr.rb
38
+ - spec/formatters
39
+ - spec/formatters/markdown_spec.rb
40
+ - spec/formatters/textile_spec.rb
41
+ - spec/presenter_spec.rb
42
+ - spec/spec_helper.rb
43
+ - spec/transfigr_spec.rb
44
+ has_rdoc: true
45
+ homepage: http://rubunity.com
46
+ post_install_message:
47
+ rdoc_options: []
48
+
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project: transfigr
66
+ rubygems_version: 1.3.1
67
+ signing_key:
68
+ specification_version: 2
69
+ summary: A Pluggable Markup Formatter
70
+ test_files: []
71
+