transfigr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+