Skip to content

Use alias chain to avoid overwriting previous attribute method declarations #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
= 0.3.2
- Put init.rb where Rails 2.3.14 expects
= 0.3
- Fixed Model.textiled = false bug
- Refactored tests
Expand Down
25 changes: 25 additions & 0 deletions acts_as_textiled.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
$LOAD_PATH.unshift 'lib'

Gem::Specification.new do |s|
s.name = "acts_as_textiled"
s.version = "0.3.2"
s.date = Time.now.strftime('%Y-%m-%d')
s.summary = "Render Textile"
s.homepage = "http://github.com/analog-analytics/acts_as_textiled"
s.email = "[email protected]"
s.authors = [ "Chris Wanstrath" ]
s.has_rdoc = false

s.files = %w( README.rdoc Rakefile )
s.files += Dir.glob("lib/**/*")
s.files += Dir.glob("bin/**/*")
s.files += Dir.glob("man/**/*")
s.files += Dir.glob("test/**/*")

s.description = <<desc
This simple plugin allows you to forget about constantly rendering Textile in
your application. Instead, you can rest easy knowing the Textile fields you
want to display as HTML will always be displayed as HTML (unless you tell your
code otherwise).
desc
end
33 changes: 24 additions & 9 deletions lib/acts_as_textiled.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ def self.included(klass)

module ClassMethods
def acts_as_textiled(*attributes)
@textiled_attributes = []

@textiled_unicode = String.new.respond_to? :chars

Expand All @@ -16,13 +15,25 @@ def acts_as_textiled(*attributes)

type_options = %w( plain source )

textiled_attributes = read_inheritable_attribute(:textiled_attributes) || []

attributes.each do |attribute|
define_method(attribute) do |*type|
type = type.first
next if textiled_attributes.include? attribute

unless method_defined?(attribute)
define_method(attribute) do |*args|
self[attribute]
end
end

if type.nil? && self[attribute]
textiled[attribute.to_s] ||= RedCloth.new(self[attribute], Array(ruled[attribute])).to_html
elsif type.nil? && self[attribute].nil?
define_method(attribute.to_s + "_with_textiled") do |*args|
type = args.first

value = __send__(attribute.to_s + "_without_textiled", *args)

if type.nil? && value
textiled[attribute.to_s] ||= RedCloth.new(value, Array(ruled[attribute])).to_html
elsif type.nil? && value.nil?
nil
elsif type_options.include?(type.to_s)
send("#{attribute}_#{type}")
Expand All @@ -31,17 +42,21 @@ def acts_as_textiled(*attributes)
end
end

alias_method_chain attribute, :textiled

define_method("#{attribute}_plain", proc { strip_redcloth_html(__send__(attribute)) if __send__(attribute) } )
define_method("#{attribute}_source", proc { __send__("#{attribute}_before_type_cast") } )

@textiled_attributes << attribute
textiled_attributes << attribute
end

write_inheritable_attribute(:textiled_attributes, textiled_attributes)

include Err::Acts::Textiled::InstanceMethods
end

def textiled_attributes
Array(@textiled_attributes)
Array(read_inheritable_attribute(:textiled_attributes))
end
end

Expand Down Expand Up @@ -74,7 +89,7 @@ def write_attribute(attr_name, value)

private
def strip_redcloth_html(html)
returning html.dup.gsub(html_regexp, '') do |h|
html.dup.gsub(html_regexp, '').tap do |h|
redcloth_glyphs.each do |(entity, char)|
sub = [ :gsub!, entity, char ]
@textiled_unicode ? h.chars.send(*sub) : h.send(*sub)
Expand Down
File renamed without changes.
22 changes: 21 additions & 1 deletion test/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
require 'yaml'
require 'mocha'
require 'active_support'
gem 'test-unit'
require 'test/spec'
require 'RedCloth'
rescue LoadError
puts "acts_as_textiled requires the mocha and test-spec gems to run its tests"
puts "acts_as_textiled requires the mocha, test-spec and RedCloth gems to run its tests"
exit
end

Expand Down Expand Up @@ -60,6 +61,13 @@ class Author < ActiveRecord::Base
end

class Story < ActiveRecord::Base
attr_reader :body_was_called

def body(*args)
@body_was_called = true
self[:body]
end

acts_as_textiled :body, :description => :lite_mode

def author
Expand All @@ -83,5 +91,17 @@ def author
end
end

class StorySubclass < Story
acts_as_textiled :body, :description => :lite_mode

def self.name
Story.name
end

def author
@author ||= Author.find(author_id)
end
end

$author = YAML.load_file(File.dirname(__FILE__) + '/fixtures/authors.yml')
$story = YAML.load_file(File.dirname(__FILE__) + '/fixtures/stories.yml')
32 changes: 28 additions & 4 deletions test/textiled_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@
specify "should enhance text attributes" do
story = Story.find(3)

body_html = %[<p><em>Textile</em> is useful because it makes text <em>slightly</em> easier to <strong>read</strong>.</p>\n\n\n\t<p>If only it were so <strong>easy</strong> to use in every programming language. In Rails,\nwith the help of <a href="http://google.com/search?q=acts_as_textiled">acts_as_textiled</a>,\nit&#8217;s way easy. Thanks in no small part to <span style="color:red;">RedCloth</span>, of course.</p>]
body_html = %[<p><em>Textile</em> is useful because it makes text <em>slightly</em> easier to <strong>read</strong>.</p>\n<p>If only it were so <strong>easy</strong> to use in every programming language. In Rails,<br />\nwith the help of <a href="http://google.com/search?q=acts_as_textiled">acts_as_textiled</a>,<br />\nit&#8217;s way easy. Thanks in no small part to <span style="color:red;">RedCloth</span>, of course.</p>]
body_textile = %[_Textile_ is useful because it makes text _slightly_ easier to *read*.\n\nIf only it were so *easy* to use in every programming language. In Rails,\nwith the help of "acts_as_textiled":http://google.com/search?q=acts_as_textiled,\nit's way easy. Thanks in no small part to %{color:red}RedCloth%, of course.\n]
body_plain = %[Textile is useful because it makes text slightly easier to read.\n\n\n\tIf only it were so easy to use in every programming language. In Rails,\nwith the help of acts_as_textiled,\nit's way easy. Thanks in no small part to RedCloth, of course.]
body_plain = %[Textile is useful because it makes text slightly easier to read.\nIf only it were so easy to use in every programming language. In Rails,\nwith the help of acts_as_textiled,\nit's way easy. Thanks in no small part to RedCloth, of course.]

story.body.should.equal body_html
story.body_source.should.equal body_textile
Expand All @@ -114,8 +114,8 @@
specify "should handle character conversions" do
story = Story.find(4)

body_html = "<p>Is Textile&#8482; the wave of the future? What about acts_as_textiled&#169;? It&#8217;s\ndoubtful. Why does Textile&#8482; smell like <em>Python</em>? Can we do anything to\nfix that? No? Well, I guess there are worse smells &#8211; like Ruby. jk.</p>\n\n\n\t<p>But seriously, ice &gt; water and water &lt; rain. But&#8230;nevermind. 1&#215;1? 1.</p>\n\n\n\t<p>&#8220;You&#8217;re a good kid,&#8221; he said. &#8220;Keep it up.&#8221;</p>"
body_plain = %[Is Textile(TM) the wave of the future? What about acts_as_textiled(C)? It's\ndoubtful. Why does Textile(TM) smell like Python? Can we do anything to\nfix that? No? Well, I guess there are worse smells-like Ruby. jk.\n\n\n\tBut seriously, ice > water and water < rain. But...nevermind. 1x1? 1.\n\n\n\t"You're a good kid," he said. "Keep it up."]
body_html = "<p>Is Textile&#8482; the wave of the future? What about acts_as_textiled&#169;? It&#8217;s<br />\ndoubtful. Why does Textile&#8482; smell like <em>Python</em>? Can we do anything to<br />\nfix that? No? Well, I guess there are worse smells &#8211; like Ruby. jk.</p>\n<p>But seriously, ice &gt; water and water &lt; rain. But&#8230;nevermind. 1 &#215; 1? 1.</p>\n<p>&#8220;You&#8217;re a good kid,&#8221; he said. &#8220;Keep it up.&#8221;</p>"
body_plain = "Is Textile(TM) the wave of the future? What about acts_as_textiled(C)? It's\ndoubtful. Why does Textile(TM) smell like Python? Can we do anything to\nfix that? No? Well, I guess there are worse smells-like Ruby. jk.\nBut seriously, ice > water and water < rain. But...nevermind. 1 x 1? 1.\n\"You're a good kid,\" he said. \"Keep it up.\""

story.body.should.equal body_html
story.body_plain.should.equal body_plain
Expand All @@ -142,4 +142,28 @@
story.textiled.size.should.equal 2
story.description.should.equal desc_html
end

specify "should define expected methods" do
story = Story.find(1)

story.body_plain.should.not.be.nil
story.body_source.should.not.be.nil
story.body_without_textiled.should.match /^Holy cats/
story.body_with_textiled.should.match /^<p>Holy cats/
story.body.should.match /^<p>Holy cats/
end

specify "should allow chaining on attributes that are already defined" do
story = Story.find(1)

story.body.should.match /^<p>Holy cats/
story.body_was_called.should.equal true
end

specify "allow subclassing and redeclaration of acts_as_textiled" do
story = StorySubclass.find(1)

story.body.should.match /^<p>Holy cats/
story.body_was_called.should.equal true
end
end