technicalpickles-has_markup 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/has_markup.rb +2 -0
- data/lib/has_markup/active_record.rb +74 -0
- data/lib/has_markup/markdown.rb +38 -0
- data/lib/has_markup/shoulda.rb +42 -0
- data/lib/has_markup/textile.rb +38 -0
- data/lib/has_markup/version.rb +7 -0
- data/test/database.yml +3 -0
- data/test/post.rb +3 -0
- data/test/post_test.rb +32 -0
- data/test/schema.rb +6 -0
- data/test/test_helper.rb +29 -0
- metadata +66 -0
data/lib/has_markup.rb
ADDED
@@ -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
|
+
errors.add column, "has #{e}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'shoulda'
|
2
|
+
|
3
|
+
module HasMarkup # :nodoc:
|
4
|
+
# Shoulda macros for has_markup. These get added to <tt>Test::Unit::TestCase</tt>.
|
5
|
+
module Shoulda
|
6
|
+
# Ensure that markup is cached.
|
7
|
+
#
|
8
|
+
# should_cache_markup :content
|
9
|
+
def should_cache_markup(column)
|
10
|
+
should_have_db_column "cached_#{column}_html"
|
11
|
+
should_have_instance_methods "set_cached_#{column}_html"
|
12
|
+
# TODO test that there's before_save action happening
|
13
|
+
end
|
14
|
+
|
15
|
+
# Ensure that markup is required.
|
16
|
+
#
|
17
|
+
# should_require_markup :content
|
18
|
+
def should_require_markup(column)
|
19
|
+
should_require_attributes column
|
20
|
+
end
|
21
|
+
|
22
|
+
# Ensure that the model has markup. Accepts all the same options that has_markup does.
|
23
|
+
#
|
24
|
+
# should_have_markup :content
|
25
|
+
def should_have_markup(column, options = {})
|
26
|
+
options = HasMarkup::default_has_markup_options.merge(options)
|
27
|
+
should_have_instance_methods "#{column}_html"
|
28
|
+
|
29
|
+
should_require_markup column if options[:required]
|
30
|
+
|
31
|
+
should_cache_markup column if options[:cache_html]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module Test # :nodoc: all
|
37
|
+
module Unit
|
38
|
+
class TestCase
|
39
|
+
extend HasMarkup::Shoulda
|
40
|
+
end
|
41
|
+
end
|
42
|
+
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
|
+
errors.add column, "has #{e}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/test/database.yml
ADDED
data/test/post.rb
ADDED
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, :required => true, :syntax => :markdown, :cache_html => true
|
5
|
+
|
6
|
+
context 'A new project without content' do
|
7
|
+
setup do
|
8
|
+
@post = Post.new
|
9
|
+
end
|
10
|
+
|
11
|
+
context "caching the content, when it's blank" do
|
12
|
+
setup do
|
13
|
+
@post.set_cached_content_html
|
14
|
+
end
|
15
|
+
|
16
|
+
should "not have cached html" do
|
17
|
+
assert_nil @post.cached_content_html
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "updating the content" do
|
22
|
+
setup do
|
23
|
+
@post.update_attributes(:content => 'hi')
|
24
|
+
end
|
25
|
+
|
26
|
+
should "now have cached html" do
|
27
|
+
assert_equal '<p>hi</p>', @post.cached_content_html
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
data/test/schema.rb
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
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
|
+
|
18
|
+
RAILS_ROOT = File.dirname(__FILE__)
|
19
|
+
require 'logger'
|
20
|
+
RAILS_DEFAULT_LOGGER = Logger.new("#{RAILS_ROOT}/test.log")
|
21
|
+
|
22
|
+
require File.dirname(__FILE__) + '/../init'
|
23
|
+
require File.dirname(__FILE__) + '/post.rb'
|
24
|
+
|
25
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
26
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
27
|
+
ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'plugin_test'])
|
28
|
+
|
29
|
+
load(File.dirname(__FILE__) + "/schema.rb") if File.exist?(File.dirname(__FILE__) + "/schema.rb")
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: technicalpickles-has_markup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josh Nichols
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-10-13 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Manage markup close to home... right in the model! Caching, validation, etc
|
17
|
+
email: josh@technicalpickles.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/has_markup
|
26
|
+
- lib/has_markup/active_record.rb
|
27
|
+
- lib/has_markup/markdown.rb
|
28
|
+
- lib/has_markup/shoulda.rb
|
29
|
+
- lib/has_markup/textile.rb
|
30
|
+
- lib/has_markup/version.rb
|
31
|
+
- lib/has_markup.rb
|
32
|
+
- test/database.yml
|
33
|
+
- test/debug.log
|
34
|
+
- test/post.rb
|
35
|
+
- test/post_test.rb
|
36
|
+
- test/schema.rb
|
37
|
+
- test/test.log
|
38
|
+
- test/test_helper.rb
|
39
|
+
has_rdoc: false
|
40
|
+
homepage: http://github.com/technicalpickles/has_markup
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.2.0
|
62
|
+
signing_key:
|
63
|
+
specification_version: 2
|
64
|
+
summary: Manage markup close to home... right in the model! Caching, validation, etc
|
65
|
+
test_files: []
|
66
|
+
|