Permalink
Browse files

initial import

  • Loading branch information...
defunkt committed Aug 10, 2006
0 parents commit cdefbea1dee9c1240e1282b1c2fb6d4b7d20f55c
Showing with 494 additions and 0 deletions.
  1. +3 −0 CHANGES
  2. +18 −0 LICENSE
  3. +121 −0 README
  4. +7 −0 about.yml
  5. +2 −0 init.rb
  6. +85 −0 lib/acts_as_textiled.rb
  7. +18 −0 test/database.yml
  8. +4 −0 test/fixtures/author.rb
  9. +8 −0 test/fixtures/authors.yml
  10. +49 −0 test/fixtures/stories.yml
  11. +4 −0 test/fixtures/story.rb
  12. +12 −0 test/memory_test_fix.rb
  13. +13 −0 test/schema.rb
  14. +35 −0 test/setup_test.rb
  15. +115 −0 test/test_textiled.rb
@@ -0,0 +1,3 @@
+= 0.1
+
+ * Initial import
18 LICENSE
@@ -0,0 +1,18 @@
+Copyright (c) 2006 Chris Wanstrath
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
121 README
@@ -0,0 +1,121 @@
+= Acts as Textiled
+
+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).
+
+No database modifications are needed.
+
+You need RedCloth, of course. And Rails.
+
+== Usage
+
+ class Story < ActiveRecord::Base
+ acts_as_textiled :body_text, :description
+ end
+
+ >> story = Story.find(3)
+ => #<Story:0x245fed8 ... >
+
+ >> story.description
+ => "<p>This is <strong>cool</strong>.</p>"
+
+ >> story.description_source
+ => "This is *cool*."
+
+ >> story.description_plain
+ => "This is cool."
+
+ >> story.description = "I _know_!"
+ => "I _know_!"
+
+ >> story.save
+ => true
+
+ >> story.description
+ => "<p>I <em>know</em>!</p>"
+
+ >> story.textiled = false
+ => false
+
+ >> story.description
+ => "I _know_!"
+
+ >> story.textiled = true
+ => true
+
+ >> story.description
+ => "<p>I <em>know</em>!</p>"
+
+=== Different Modes
+
+RedCloth supports different modes, such as :lite_mode. To use a mode on
+a specific attribute simply pass it in as an options hash after any
+attributes you don't want to mode-ify. Like so:
+
+ class Story < ActiveRecord::Base
+ acts_as_textiled :body_text, :description => :lite_mode
+ end
+
+Or:
+
+ class Story < ActiveRecord::Base
+ acts_as_textiled :body_text => :lite_mode, :description => :lite_mode
+ end
+
+You can also pass in multiple modes per attribute:
+
+ class Story < ActiveRecord::Base
+ acts_as_textiled :body_text, :description => [ :lite_mode, :no_span_caps ]
+ end
+
+Get it? Now let's say you have an admin tool and you want the text to be displayed
+in the text boxes / fields as plaintext. Do you have to change all your views?
+
+Hell no.
+
+=== form_for
+
+Are you using form_for? If you are, you don't have to change any code at all.
+
+ <% form_for :story, @story do |f| %>
+ Description: <br/> <%= f.text_field :description %>
+ <% end %>
+
+You'll see the Textile plaintext in the text field. It Just Works.
+
+=== form tags
+
+If you're being a bit unconvential, no worries. You can still get at your
+raw Textile like so:
+
+ Description: <br/> <%= text_field_tag :description, @story.description_source %>
+
+And there's always object.textiled = false, as demo'd above.
+
+== Pre-fetching
+
+acts_as_textiled locally caches rendered HTML once the attribute in question has
+been requested. Obviously this doesn't bode well for marshalling or caching.
+
+If you need to force your object to build and cache HTML for all textiled attributes,
+call the +textilize+ method on your object.
+
+If you're real crazy you can even do something like this:
+
+ class Story < ActiveRecord::Base
+ acts_as_textiled :body_text, :description
+
+ def after_find
+ textilize
+ end
+ end
+
+All your Textile will now be ready to go in spiffy HTML format. But you probably
+won't need to do this.
+
+Enjoy.
+
+>> Chris Wanstrath
+=> chris[at]ozmm[dot]org
@@ -0,0 +1,7 @@
+author: Chris Wanstrath (chris[at]ozmm[dot]org)
+summary:
+homepage: http://errtheblog.com/post/14
+plugin: http://require.errtheblog.com/svn/acts_as_textiled
+license: MIT
+version: 0.1
+rails_version: 1.1+
@@ -0,0 +1,2 @@
+require 'acts_as_textiled'
+ActiveRecord::Base.send(:include, Err::Acts::Textiled)
@@ -0,0 +1,85 @@
+module Err
+ module Acts #:nodoc: all
+ module Textiled
+ def self.included(klass)
+ klass.extend ClassMethods
+ end
+
+ module ClassMethods
+ def acts_as_textiled(*attrs)
+ ruled = attrs.last.is_a?(Hash) ? attrs.pop : {}
+ attrs += ruled.keys
+
+ attrs.each do |attr|
+ define_method(attr) do
+ textiled[attr.to_s] ||= RedCloth.new(read_attribute(attr), Array(ruled[attr])).to_html
+ end
+ define_method("#{attr}_plain", proc { strip_redcloth_html(__send__(attr)) } )
+ define_method("#{attr}_source", proc { __send__("#{attr}_before_type_cast") } )
+ end
+
+ include Err::Acts::Textiled::InstanceMethods
+ end
+ end
+
+ module InstanceMethods
+ def textiled
+ textiled? ? (@textiled ||= {}) : @attributes.dup
+ end
+
+ def textiled?
+ @is_textiled.nil? ? true : @is_textiled
+ end
+
+ def textiled=(bool)
+ @is_textiled = !!bool
+ end
+
+ def textilize
+ logger.debug "I GOT HIT!"
+ attribute_names.each { |attr| __send__(attr) }
+ end
+
+ def reload
+ textiled.clear
+ super
+ end
+
+ def write_attribute(attr_name, value)
+ textiled[attr_name.to_s] = nil
+ super(attr_name, value)
+ end
+
+ private
+ def strip_redcloth_html(html)
+ html.gsub!(html_regexp, '')
+ redcloth_glyphs.each do |(entity, char)|
+ html.gsub!(entity, char)
+ end
+ html
+ end
+
+ def redcloth_glyphs
+ [[ '&#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
@@ -0,0 +1,18 @@
+sqlite:
+ :adapter: sqlite
+ :dbfile: ':memory:'
+sqlite3:
+ :adapter: sqlite3
+ :dbfile: ':memory:'
+postgresql:
+ :adapter: postgresql
+ :username: postgres
+ :password: postgres
+ :database: acts_as_textiled_plugin_test
+ :min_messages: ERROR
+mysql:
+ :adapter: mysql
+ :host: localhost
+ :username: root
+ :password:
+ :database: acts_as_textiled_plugin_test
@@ -0,0 +1,4 @@
+class Author < ActiveRecord::Base
+ has_many :stories
+ acts_as_textiled :blog => :lite_mode
+end
@@ -0,0 +1,8 @@
+why:
+ id: 1
+ name: why the lucky stiff
+ blog: '"RedHanded":http://redhanded.hobix.com'
+defunkt:
+ id: 2
+ name: Chris Wanstrath
+ blog: '"ones zeros majors and minors":http://ozmm.org'
@@ -0,0 +1,49 @@
+sandbox:
+ id: 1
+ author_id: 1
+ title: The Thrilling Freaky-Freaky Sandbox Hack
+ body: Holy cats, I'm proud to offer you this sensational hack today. For me, this is monumental, as it culminates a number of sundry microhacks from the past few years and gets us a step closer to realizing Try Ruby out in the broader kingdoms. This is the sort of thing that will make you want to post spangly angel GIFs in the comments.
+ description: _why announces __Sandbox__
+irb:
+ id: 2
+ author_id: 2
+ title: Simpler IRB
+ description: __Beautify__ your *IRb* prompt
+ body: |
+ Sick of that ugly irb prompt? Too much information.
+
+ $ irb
+ irb(main):001:0> "i dont care how deeply nested i yam".nil?
+ => false
+ Check it. Stick this in your .irbrc:
+
+ IRB.conf[:PROMPT_MODE] = :SIMPLE
+ Now we get a prompt which is, well, simple:
+
+ $ irb
+ >> !!nil
+ => false
+ Less noise.
+textile:
+ id: 3
+ author_id: 2
+ title: I am a fan of Textile.
+ description: Chris explains why Textile is useful.
+ body: |
+ _Textile_ is useful because it makes text _slightly_ easier to *read*.
+
+ If only it were so *easy* to use in every programming language. In Rails,
+ with the help of "acts_as_textiled":http://google.com/search?q=acts_as_textiled,
+ it's way easy. Thanks in no small part to %{color:red}RedCloth%, of course.
+legalize:
+ id: 4
+ author_id: 2
+ title: This is a bunch of text about things.
+ body: |
+ Is Textile(TM) the wave of the future? What about acts_as_textiled(C)? It's
+ doubtful. Why does Textile(TM) smell like _Python_? Can we do anything to
+ fix that? No? Well, I guess there are worse smells - like Ruby. jk.
+
+ But seriously, ice > water and water < rain. But...nevermind. 1 x 1? 1.
+
+ "You're a good kid," he said. "Keep it up."
@@ -0,0 +1,4 @@
+class Story < ActiveRecord::Base
+ belongs_to :author
+ acts_as_textiled :body, :description => :lite_mode
+end
@@ -0,0 +1,12 @@
+# MemoryTestFix
+def in_memory_database?
+ ENV["RAILS_ENV"] == "test" and
+ ActiveRecord::Base.connection.class == ActiveRecord::ConnectionAdapters::SQLiteAdapter and
+ Rails::Configuration.new.database_configuration['test']['database'] == ':memory:'
+end
+
+if in_memory_database?
+ puts "Creating sqlite in memory database"
+ load "#{RAILS_ROOT}/db/schema.rb" # use db agnostic schema by default
+# ActiveRecord::Migrator.up('db/migrate') # use migrations
+end
@@ -0,0 +1,13 @@
+ActiveRecord::Schema.define(:version => 0) do
+ create_table :stories, :force => true do |t|
+ t.column :title, :string
+ t.column :description, :string
+ t.column :body, :text
+ t.column :author_id, :integer
+ end
+
+ create_table :authors, :force => true do |t|
+ t.column :name, :string
+ t.column :blog, :string
+ end
+end
@@ -0,0 +1,35 @@
+# borrowed from topfunky and scott barron, thanks
+require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
+require 'active_record/fixtures'
+require File.join(File.dirname(__FILE__), 'fixtures/story')
+require File.join(File.dirname(__FILE__), 'fixtures/author')
+require File.join(File.dirname(__FILE__), 'memory_test_fix')
+require 'test/unit'
+
+config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
+ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
+ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite3'])
+
+load(File.dirname(__FILE__) + "/schema.rb")
+
+Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
+$LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
+
+
+class Test::Unit::TestCase #:nodoc:
+ def create_fixtures(*table_names)
+ if block_given?
+ Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
+ else
+ Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
+ end
+ end
+
+ # Turn off transactional fixtures if you're working with MyISAM tables in MySQL
+ self.use_transactional_fixtures = true
+
+ # Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)
+ self.use_instantiated_fixtures = false
+
+ # Add more helper methods to be used by all tests here...
+end
Oops, something went wrong.

0 comments on commit cdefbea

Please sign in to comment.