public
Description: Makes your models act as textiled.
Homepage: http://errtheblog.com/posts/12-actsastextiled
Clone URL: git://github.com/defunkt/acts_as_textiled.git
Click here to lend your support to: acts_as_textiled and make a donation at www.pledgie.com !
acts_as_textiled / lib / acts_as_textiled.rb
100644 133 lines (107 sloc) 3.807 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
module Err
  module Acts #:nodoc: all
    module Textiled
      include ActionView::Helpers::TagHelper
      include ActionView::Helpers::TextHelper
 
      def self.included(klass)
        klass.extend ClassMethods
      end
 
      module ClassMethods
        def acts_as_textiled(*attributes)
          @textiled_attributes = []
 
          @textiled_unicode = String.new.respond_to? :chars
 
          ruled = attributes.last.is_a?(Hash) ? attributes.pop : {}
          attributes += ruled.keys
 
          type_options = %w( plain source )
 
          attributes.each do |attribute|
            define_method(attribute) do |*type|
              type = type.first
 
              if type.nil? && self[attribute]
                t = textiled[attribute.to_s]
                if t.nil?
                  str = self[attribute]
 
                  # suck out script stuff
                  str.gsub!(/\<(java)?script\>(.*?)\<\/(java)?script\>/i) do |match|
                    CGI.escapeHTML(match)
                  end
 
                  str = auto_link(str, :all) do |txt|
                    txt.size < 55 ? txt : truncate(txt, :length => 50)
                  end
 
                  str = RedCloth.new(str, Array(ruled[attribute])).to_html
 
                  # preserve whitespace for haml
                  str = str.chomp("\n").gsub(/\n/, '&#x000A;').gsub(/\r/, '')
 
                  textiled[attribute.to_s] = t = str
                end
                t
              elsif type.nil? && self[attribute].nil?
                nil
              elsif type_options.include?(type.to_s)
                send("#{attribute}_#{type}")
              else
                raise "I don't understand the `#{type}' option. Try #{type_options.join(' or ')}."
              end
            end
 
            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
          end
 
          include Err::Acts::Textiled::InstanceMethods
        end
 
        def textiled_attributes
          Array(@textiled_attributes)
        end
      end
 
      module InstanceMethods
        def textiled
          textiled? ? (@textiled ||= {}) : @attributes.dup
        end
 
        def textiled?
          @is_textiled != false
        end
 
        def textiled=(bool)
          @is_textiled = !!bool
        end
 
        def textilize
          self.class.textiled_attributes.each { |attr| __send__(attr) }
        end
 
        def reload(options = nil)
          textiled.clear
          super
        end
 
        def write_attribute(attr_name, value)
          textiled[attr_name.to_s] = nil
          super
        end
 
      private
        def strip_redcloth_html(html)
          returning html.dup.gsub(html_regexp, '') do |h|
            redcloth_glyphs.each do |(entity, char)|
              sub = [ :gsub!, entity, char ]
              @textiled_unicode ? h.chars.send(*sub) : h.send(*sub)
            end
          end
        end
 
        def redcloth_glyphs
           [[ '&#x000A;', "\n"],
            [ '&#8217;', "'" ],
            [ '&#8216;', "'" ],
            [ '&lt;', '<' ],
            [ '&gt;', '>' ],
            [ '&#8221;', '"' ],
            [ '&#8220;', '"' ],
            [ '&#8230;', '...' ],
            [ '\1&#8212;', '--' ],
            [ ' &rarr; ', '->' ],
            [ ' &#8211; ', '-' ],
            [ '&#215;', 'x' ],
            [ '&#8482;', '(TM)' ],
            [ '&#174;', '(R)' ],
            [ '&#169;', '(C)' ]]
        end
 
        def html_regexp
          %r{<(?:[^>"']+|"(?:\\.|[^\\"]+)*"|'(?:\\.|[^\\']+)*')*>}xm
        end
      end
    end
  end
end