has_markup 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ test/*.log
2
+ rdoc
3
+ *.swp
4
+ *.swo
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Josh Nichols
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 ADDED
@@ -0,0 +1,42 @@
1
+ = HasMarkup
2
+
3
+ I don't know about you, but I'm not too much of a fan of writing out raw HTML when I'm trying to belt out some blog posts. Keeping track of those pesky closing tags, escaping entities, and so on, can really get in the way of your creativity.
4
+
5
+ As a result, most blogs provide a simplified markup or some sort of editor. For technicalpickles.com[http://technicalpickles.com], I went with markdown[http://daringfireball.net/projects/markdown/].
6
+
7
+ I extracted this markup magic out of my blog, and this plugin is the result. It lets you:
8
+
9
+ * Specify a column contains markup
10
+ * Specify the syntax (markdown and textile, with markdown being the default)
11
+ * Specify if the markup column is required
12
+ * Generate a helper for generating the HTML
13
+ * Specify if the HTML should be cached in the database
14
+ * ... all using only one line
15
+
16
+ == Example
17
+
18
+ In your model:
19
+
20
+ class Post
21
+ has_markup :content, :syntax => :markdown, :required => true, :cache_html => true
22
+ end
23
+
24
+ Now post will have a 'content_html' method for generating the
25
+
26
+ So, you can use it in your view:
27
+
28
+ <h2><%= h @post.title %></h2>
29
+ <div>
30
+ <%= @post.cached_content_html %>
31
+ </div>
32
+
33
+ And you can test it easily using Shoulda:
34
+
35
+ require 'has_markup/shoulda'
36
+ class PostTest < Test::Unit::TestCase
37
+ should_have_markup :content, :syntax => :markdown, :required => true, :cache_html => true
38
+ end
39
+
40
+ == License
41
+
42
+ Copyright (c) 2008 Josh Nichols, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |s|
7
+ s.name = "has_markup"
8
+ s.summary = "Manage markup close to home... right in the model! Caching, validation, etc"
9
+ s.email = "josh@technicalpickles.com"
10
+ s.authors = ["Josh Nichols"]
11
+ s.homepage = "http://github.com/technicalpickles/has_markup"
12
+ s.description = "Manage markup close to home... right in the model! Caching, validation, etc"
13
+ s.version = "0.1.5"
14
+ s.files.exclude('vendor/**/*')
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+
18
+ Rake::TestTask.new do |t|
19
+ t.libs << 'lib'
20
+ t.pattern = 'test/**/*_test.rb'
21
+ t.verbose = false
22
+ end
23
+
24
+ desc 'Generate documentation for the safety_valve plugin.'
25
+ Rake::RDocTask.new(:rdoc) do |rdoc|
26
+ rdoc.rdoc_dir = 'rdoc'
27
+ rdoc.title = 'HasMarkup'
28
+ rdoc.options << '--line-numbers' << '--inline-source'
29
+ rdoc.rdoc_files.include('README*')
30
+ rdoc.rdoc_files.include('lib/**/*.rb')
31
+ end
32
+
33
+ desc "Run the test suite"
34
+ task :default => :test
@@ -0,0 +1,60 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{has_markup}
8
+ s.version = "0.1.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Josh Nichols"]
12
+ s.date = %q{2010-03-07}
13
+ s.description = %q{Manage markup close to home... right in the model! Caching, validation, etc}
14
+ s.email = %q{josh@technicalpickles.com}
15
+ s.extra_rdoc_files = [
16
+ "README"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "MIT-LICENSE",
21
+ "README",
22
+ "Rakefile",
23
+ "has_markup.gemspec",
24
+ "init.rb",
25
+ "lib/has_markup.rb",
26
+ "lib/has_markup/active_record.rb",
27
+ "lib/has_markup/markdown.rb",
28
+ "lib/has_markup/textile.rb",
29
+ "lib/has_markup/version.rb",
30
+ "shoulda_macros/has_markup.rb",
31
+ "tasks/has_markup_tasks.rake",
32
+ "test/database.yml",
33
+ "test/post.rb",
34
+ "test/post_test.rb",
35
+ "test/schema.rb",
36
+ "test/test_helper.rb"
37
+ ]
38
+ s.homepage = %q{http://github.com/technicalpickles/has_markup}
39
+ s.rdoc_options = ["--charset=UTF-8"]
40
+ s.require_paths = ["lib"]
41
+ s.rubygems_version = %q{1.3.6}
42
+ s.summary = %q{Manage markup close to home... right in the model! Caching, validation, etc}
43
+ s.test_files = [
44
+ "test/post.rb",
45
+ "test/post_test.rb",
46
+ "test/schema.rb",
47
+ "test/test_helper.rb"
48
+ ]
49
+
50
+ if s.respond_to? :specification_version then
51
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
52
+ s.specification_version = 3
53
+
54
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
55
+ else
56
+ end
57
+ else
58
+ end
59
+ end
60
+
data/init.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'has_markup'
2
+
3
+ if defined? ThoughtBot::Shoulda
4
+ require 'has_markup/shoulda'
5
+ end
data/lib/has_markup.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'has_markup/markdown'
2
+ require 'has_markup/active_record'
@@ -0,0 +1,74 @@
1
+ module HasMarkup
2
+ # Modules to extend ActiveRecord
3
+ module ActiveRecord #:nodoc:
4
+ # Methods that are added to ActiveRecord::Base
5
+ module ClassMethods
6
+ # Adds the following methods for dealing with markup, using <tt>has_markup :content</tt> as an example:
7
+ # * <tt>content_html</tt> for generating the html of <tt>:content</tt>.
8
+ #
9
+ # Options are:
10
+ # * <tt>:required</tt> - column is required
11
+ # * <tt>:syntax</tt> - syntax of the markup. Currently supports only :markdown, which is the default.
12
+ # * <tt>:cache_html</tt> - html generated from the markup should be cached in a column. Following the
13
+ # example of using <tt>:content</tt>, it would require a column named <tt>:cached_content_html</tt>.
14
+ # It also adds a before_save hook <tt>:cache_content_html</tt> for generating the html before saving.
15
+ #
16
+ # For adding additional syntaxes, see has_markup/markdown and has_markup/textile. Basically:
17
+ #
18
+ # * Create HasMarkup::SyntaxNameHere
19
+ # * Define sprinkle_syntax_name_here_magic which takes a column name, like <tt>:content</tt>
20
+ # * In sprinkle_syntax_name_here_magic, create <tt>"#{column}_html"</tt>, which handles the actual generation
21
+ def has_markup(column, options = {})
22
+ options = HasMarkup::default_has_markup_options.merge(options)
23
+
24
+ validates_presence_of column if options[:required]
25
+
26
+ syntax = options[:syntax]
27
+ if supported? syntax
28
+ extend markup_syntax_module(syntax)
29
+ send("sprinkle_#{syntax}_magic", column)
30
+ else
31
+ raise "Unsupported syntax #{syntax.inspect}."
32
+ end
33
+ sprinkle_html_caching_magic column if options[:cache_html]
34
+ end
35
+
36
+ # Is the given syntax supported?
37
+ def supported?(syntax)
38
+ begin
39
+ markup_syntax_module(syntax)
40
+ return true
41
+ rescue NameError
42
+ return false
43
+ end
44
+ end
45
+
46
+ def markup_syntax_module(syntax)
47
+ "HasMarkup::#{syntax.to_s.camelize}".constantize
48
+ end
49
+
50
+
51
+ # Sprinkles the magic for caching the html of the given
52
+ def sprinkle_html_caching_magic(column)
53
+ define_method "set_cached_#{column}_html" do
54
+ html = self.send("#{column}_html")
55
+ self.send("cached_#{column}_html=", html)
56
+ end
57
+ before_save "set_cached_#{column}_html".to_sym
58
+ end
59
+ end
60
+ end
61
+
62
+ def self.default_has_markup_options
63
+ {
64
+ :syntax => :markdown,
65
+ :required => false,
66
+ :cache_html => false
67
+ }
68
+ end
69
+ end
70
+
71
+ require 'active_record'
72
+ ActiveRecord::Base.class_eval do
73
+ extend HasMarkup::ActiveRecord::ClassMethods
74
+ end
@@ -0,0 +1,38 @@
1
+ module HasMarkup
2
+ # Provides HasMarkup with markdown[http://daringfireball.net/projects/markdown/] support.
3
+ module Markdown
4
+ # Sprinkles the magic needed to support markdown. In particular, it will validate the markdown syntax
5
+ # on the column, and define a method <tt>column_html</tt> which uses BlueCloth to generate HTML.
6
+ def sprinkle_markdown_magic(column)
7
+ require 'bluecloth'
8
+
9
+ extend HasMarkup::Markdown::ClassMethods
10
+ include HasMarkup::Markdown::InstanceMethods
11
+
12
+ validates_markdown_syntax column
13
+ define_method "#{column}_html" do
14
+ markdown = self.send(column)
15
+ self.generate_html_from_markdown(markdown)
16
+ end
17
+ end
18
+
19
+ module InstanceMethods
20
+ def generate_html_from_markdown(markdown)
21
+ BlueCloth.new(markdown).to_html unless markdown.blank?
22
+ end
23
+ end
24
+
25
+ module ClassMethods
26
+ # Validates the markdown syntax of the given columns.
27
+ def validates_markdown_syntax(*columns)
28
+ validates_each(*columns) do |record, column, value|
29
+ begin
30
+ record.generate_html_from_markdown(value)
31
+ rescue BlueCloth::FormatError => e
32
+ record.errors.add column, "has #{e}"
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ module HasMarkup
2
+ # Provides HasMarkup with textile[http://hobix.com/textile/] support
3
+ module Textile
4
+ # Sprinkles the magic needed to support textile. In particular, it will define a method <tt>column_html</tt> which uses RedCloth to
5
+ # generate HTML.
6
+ def sprinkle_textile_magic(column)
7
+ require 'redcloth'
8
+
9
+ extend HasMarkup::Textile::ClassMethods
10
+ include HasMarkup::Textile::InstanceMethods
11
+
12
+ validates_textile_syntax column
13
+ define_method "#{column}_html" do
14
+ markdown = self.send(column)
15
+ self.generate_html_from_markdown(markdown)
16
+ end
17
+ end
18
+
19
+ module InstanceMethods
20
+ def generate_html_from_markdown(textile)
21
+ RedCloth.new(textile).to_html unless textile.blank?
22
+ end
23
+ end
24
+
25
+ module ClassMethods
26
+ # Validates the markdown syntax of the given columns.
27
+ def validates_textile_syntax(*columns)
28
+ validates_each(*columns) do |record, column, value|
29
+ begin
30
+ record.generate_html_from_markdown(value)
31
+ rescue e
32
+ record.errors.add column, "has #{e}"
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ module HasMarkup
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ PATCH = 1
6
+ end
7
+ end
@@ -0,0 +1,37 @@
1
+ module HasMarkup # :nodoc:
2
+ # Shoulda macros for has_markup. These get added to <tt>Test::Unit::TestCase</tt>.
3
+ module Shoulda
4
+ # Ensure that markup is cached.
5
+ #
6
+ # should_cache_markup :content
7
+ def should_cache_markup(column)
8
+ should_have_db_column "cached_#{column}_html"
9
+ should_have_instance_methods "set_cached_#{column}_html"
10
+ # TODO test that there's before_save action happening
11
+ end
12
+
13
+ # Ensure that markup is required.
14
+ #
15
+ # should_require_markup :content
16
+ def should_require_markup(column)
17
+ should_validate_presence_of column
18
+ end
19
+
20
+ # Ensure that the model has markup. Accepts all the same options that has_markup does.
21
+ #
22
+ # should_have_markup :content
23
+ def should_have_markup(column, options = {})
24
+ options = HasMarkup::default_has_markup_options.merge(options)
25
+ should_have_instance_methods "#{column}_html"
26
+
27
+ should_require_markup column if options[:required]
28
+
29
+ should_cache_markup column if options[:cache_html]
30
+ end
31
+ end
32
+ end
33
+
34
+ class Test::Unit::TestCase # :nodoc:
35
+ extend HasMarkup::Shoulda
36
+ end
37
+
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :has_markup do
3
+ # # Task goes here
4
+ # end
data/test/database.yml ADDED
@@ -0,0 +1,3 @@
1
+ plugin_test:
2
+ adapter: sqlite3
3
+ database: ':memory:'
data/test/post.rb ADDED
@@ -0,0 +1,3 @@
1
+ class Post < ActiveRecord::Base
2
+ has_markup :content, :required => true, :syntax => :markdown, :cache_html => true
3
+ end
data/test/post_test.rb ADDED
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class PostTest < Test::Unit::TestCase
4
+ should_have_markup :content,
5
+ :required => true,
6
+ :syntax => :markdown,
7
+ :cache_html => true
8
+
9
+ context 'A new project without content' do
10
+ setup { @post = Post.new }
11
+
12
+ context "caching the content, when it's blank" do
13
+ setup do
14
+ @post.set_cached_content_html
15
+ end
16
+
17
+ should "not have cached html" do
18
+ assert_nil @post.cached_content_html
19
+ end
20
+ end
21
+
22
+ context "updating the content" do
23
+ setup do
24
+ @post.update_attributes(:content => 'hi')
25
+ end
26
+
27
+ should "now have cached html" do
28
+ assert_equal '<p>hi</p>', @post.cached_content_html
29
+ end
30
+ end
31
+ end
32
+ end
data/test/schema.rb ADDED
@@ -0,0 +1,6 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :posts, :force => true do |t|
3
+ t.text :content
4
+ t.text :cached_content_html
5
+ end
6
+ end
@@ -0,0 +1,30 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'rubygems'
4
+
5
+ # Use vendored gem because of limited gem availability on runcoderun
6
+ # This is loosely based on 'vendor everything'.
7
+ Dir[File.join(File.dirname(__FILE__), '..', 'vendor', 'gems', '**')].each do |dir|
8
+ lib = "#{dir}/lib"
9
+ $LOAD_PATH.unshift(lib) if File.directory?(lib)
10
+ end
11
+
12
+ require 'test/unit'
13
+ require 'active_record'
14
+ require 'shoulda'
15
+ require 'shoulda/active_record'
16
+ require 'factory_girl'
17
+ require File.dirname(__FILE__) + '/../shoulda_macros/has_markup'
18
+
19
+ RAILS_ROOT = File.dirname(__FILE__)
20
+ require 'logger'
21
+ RAILS_DEFAULT_LOGGER = Logger.new("#{RAILS_ROOT}/test.log")
22
+
23
+ require File.dirname(__FILE__) + '/../init'
24
+ require File.dirname(__FILE__) + '/post'
25
+
26
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
27
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
28
+ ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'plugin_test'])
29
+
30
+ load(File.dirname(__FILE__) + "/schema.rb") if File.exist?(File.dirname(__FILE__) + "/schema.rb")
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has_markup
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 5
9
+ version: 0.1.5
10
+ platform: ruby
11
+ authors:
12
+ - Josh Nichols
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-07 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Manage markup close to home... right in the model! Caching, validation, etc
22
+ email: josh@technicalpickles.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README
29
+ files:
30
+ - .gitignore
31
+ - MIT-LICENSE
32
+ - README
33
+ - Rakefile
34
+ - has_markup.gemspec
35
+ - init.rb
36
+ - lib/has_markup.rb
37
+ - lib/has_markup/active_record.rb
38
+ - lib/has_markup/markdown.rb
39
+ - lib/has_markup/textile.rb
40
+ - lib/has_markup/version.rb
41
+ - shoulda_macros/has_markup.rb
42
+ - tasks/has_markup_tasks.rake
43
+ - test/database.yml
44
+ - test/post.rb
45
+ - test/post_test.rb
46
+ - test/schema.rb
47
+ - test/test_helper.rb
48
+ has_rdoc: true
49
+ homepage: http://github.com/technicalpickles/has_markup
50
+ licenses: []
51
+
52
+ post_install_message:
53
+ rdoc_options:
54
+ - --charset=UTF-8
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.3.6
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: Manage markup close to home... right in the model! Caching, validation, etc
78
+ test_files:
79
+ - test/post.rb
80
+ - test/post_test.rb
81
+ - test/schema.rb
82
+ - test/test_helper.rb