godfat-friendly_format 0.6.0 → 0.6.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/CHANGES +10 -1
- data/README +4 -4
- data/Rakefile +16 -32
- data/TODO +0 -1
- data/friendly_format.gemspec +7 -11
- data/lib/friendly_format/adapter/abstract.rb +31 -0
- data/lib/friendly_format/{adapters → adapter}/hpricot_adapter.rb +5 -13
- data/lib/friendly_format/adapter/libxml_adapter.rb +25 -0
- data/lib/friendly_format/adapter/nokogiri_adapter.rb +21 -0
- data/lib/friendly_format/set_common.rb +5 -5
- data/lib/friendly_format/set_strict.rb +2 -2
- data/lib/friendly_format/version.rb +1 -1
- data/lib/friendly_format.rb +74 -52
- data/test/sample/complex_article_result.txt +45 -45
- data/test/test_friendly_format.rb +89 -25
- metadata +11 -16
- data/lib/friendly_format/adapters/libxml_adapter.rb +0 -46
- data/lib/friendly_format/adapters/nokogiri_adapter.rb +0 -31
data/CHANGES
CHANGED
@@ -1,8 +1,17 @@
|
|
1
1
|
= friendly_format changes history
|
2
2
|
|
3
|
-
== friendly_format 0.6.
|
3
|
+
== friendly_format 0.6.1 / 2009-04-05
|
4
4
|
|
5
5
|
* added nokogiri and libxml-ruby support.
|
6
|
+
* drop support for hpricot < 0.7
|
7
|
+
* you can explicitly choose adapter, or auto-choose:
|
8
|
+
1. hpricot or falls back to:
|
9
|
+
2. nokogiri or falls back to:
|
10
|
+
3. libxml-ruby
|
11
|
+
* now internally, we store string instead of symbol
|
12
|
+
for accepted tags to prevent from symbol explosion.
|
13
|
+
* ruby 1.9 compliant
|
14
|
+
* escape gt(>) in pre tag and forbidden tag as well.
|
6
15
|
|
7
16
|
== friendly_format 0.5.1 / 2008-12-11
|
8
17
|
|
data/README
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= friendly_format 0.6
|
1
|
+
= friendly_format 0.6.1
|
2
2
|
by Lin Jen-Shin (a.k.a. godfat-真常[http://godfat.org])
|
3
3
|
godfat (XD) godfat.org
|
4
4
|
|
@@ -24,9 +24,9 @@ by Lin Jen-Shin (a.k.a. godfat-真常[http://godfat.org])
|
|
24
24
|
|
25
25
|
== REQUIREMENTS:
|
26
26
|
|
27
|
-
* hpricot >=0.
|
28
|
-
* nokogiri >=1.
|
29
|
-
* libxml-ruby >=
|
27
|
+
* hpricot >=0.7 or
|
28
|
+
* nokogiri >=1.2 or
|
29
|
+
* libxml-ruby >=1.1
|
30
30
|
|
31
31
|
== INSTALL:
|
32
32
|
|
data/Rakefile
CHANGED
@@ -1,47 +1,26 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
Bones.setup
|
6
|
-
rescue LoadError
|
7
|
-
load 'tasks/setup.rb' # this line should already be there
|
8
|
-
end
|
3
|
+
require 'bones'
|
4
|
+
Bones.setup
|
9
5
|
|
10
6
|
PROJ.name = 'friendly_format'
|
11
|
-
|
12
|
-
|
7
|
+
PROJ.authors = 'Lin Jen-Shin (a.k.a. godfat 真常)'
|
8
|
+
PROJ.email = 'godfat (XD) godfat.org'
|
9
|
+
PROJ.url = "http://github.com/godfat/#{PROJ.name}"
|
10
|
+
PROJ.rubyforge.name = 'ludy'
|
13
11
|
|
14
|
-
|
15
|
-
PROJ.gem.development_dependencies << ['minitest', '>=1.3'] <<
|
16
|
-
['hpricot', '>=0.6'] <<
|
12
|
+
PROJ.gem.development_dependencies << ['hpricot', '>=0.6'] <<
|
17
13
|
['nokogiri', '>=1.1'] <<
|
18
14
|
['libxml-ruby', '>=0.9']
|
19
|
-
# PROJ.gem.executables = ["bin/#{PROJ.name}"]
|
20
|
-
|
21
|
-
task :default do
|
22
|
-
Rake.application.options.show_task_pattern = /./
|
23
|
-
Rake.application.display_tasks_and_comments
|
24
|
-
end
|
25
15
|
|
26
|
-
|
27
|
-
desc "create #{PROJ.name}.gemspec"
|
28
|
-
task 'gemspec' do
|
29
|
-
puts "rake gem:debug > #{PROJ.name}.gemspec"
|
30
|
-
File.open("#{PROJ.name}.gemspec", 'w'){|spec| spec << `rake gem:debug`.sub(/.*/, '')}
|
31
|
-
end
|
32
|
-
end
|
16
|
+
# PROJ.ruby_opts.delete '-w'
|
33
17
|
|
34
|
-
PROJ.authors = 'Lin Jen-Shin (a.k.a. godfat 真常)'
|
35
|
-
PROJ.email = 'godfat (XD) godfat.org'
|
36
|
-
PROJ.url = "http://github.com/godfat/#{PROJ.name}"
|
37
18
|
PROJ.description = PROJ.summary = paragraphs_of('README', 'description').join("\n\n")
|
38
19
|
PROJ.changes = paragraphs_of('CHANGES', 0..1).join("\n\n")
|
39
|
-
PROJ.rubyforge.name = 'ludy'
|
40
20
|
PROJ.version = File.read("lib/#{PROJ.name}/version.rb").gsub(/.*VERSION = '(.*)'.*/m, '\1')
|
41
21
|
|
42
|
-
PROJ.
|
43
|
-
|
44
|
-
'^\.gitignore$', '^ann-', '\.sqlite3$', '\.db$']
|
22
|
+
PROJ.exclude += ['^tmp', 'tmp$', '^pkg', '^\.gitignore$',
|
23
|
+
'^ann-', '\.sqlite3$', '\.db$']
|
45
24
|
|
46
25
|
PROJ.rdoc.remote_dir = PROJ.name
|
47
26
|
|
@@ -49,7 +28,7 @@ PROJ.readme_file = 'README'
|
|
49
28
|
PROJ.rdoc.main = 'README'
|
50
29
|
PROJ.rdoc.exclude += ['Rakefile', '^tasks', '^test']
|
51
30
|
PROJ.rdoc.include << '\w+'
|
52
|
-
PROJ.rdoc.opts << '--diagram' if !
|
31
|
+
# PROJ.rdoc.opts << '--diagram' if !Rake::Win32 and `which dot` =~ %r/\/dot/
|
53
32
|
PROJ.rdoc.opts += ['--charset=utf-8', '--inline-source',
|
54
33
|
'--line-numbers', '--promiscuous']
|
55
34
|
|
@@ -59,3 +38,8 @@ PROJ.ann.file = "ann-#{PROJ.name}-#{PROJ.version}"
|
|
59
38
|
PROJ.ann.paragraphs.concat %w[LINKS SYNOPSIS REQUIREMENTS INSTALL LICENSE]
|
60
39
|
|
61
40
|
CLEAN.include Dir['**/*.rbc']
|
41
|
+
|
42
|
+
task :default do
|
43
|
+
Rake.application.options.show_task_pattern = /./
|
44
|
+
Rake.application.display_tasks_and_comments
|
45
|
+
end
|
data/TODO
CHANGED
data/friendly_format.gemspec
CHANGED
@@ -1,20 +1,19 @@
|
|
1
|
-
|
2
1
|
# -*- encoding: utf-8 -*-
|
3
2
|
|
4
3
|
Gem::Specification.new do |s|
|
5
4
|
s.name = %q{friendly_format}
|
6
|
-
s.version = "0.6.
|
5
|
+
s.version = "0.6.1"
|
7
6
|
|
8
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
8
|
s.authors = ["Lin Jen-Shin (a.k.a. godfat \347\234\237\345\270\270)"]
|
10
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-04-05}
|
11
10
|
s.description = %q{make user input be valid xhtml and format it with gsub("\n", "<br/>") etc. you can partially allow some tags and don't escape them.}
|
12
11
|
s.email = %q{godfat (XD) godfat.org}
|
13
12
|
s.extra_rdoc_files = ["CHANGES", "LICENSE", "NOTICE", "README", "TODO", "friendly_format.gemspec"]
|
14
|
-
s.files = ["CHANGES", "LICENSE", "NOTICE", "README", "Rakefile", "TODO", "friendly_format.gemspec", "lib/friendly_format.rb", "lib/friendly_format/
|
13
|
+
s.files = ["CHANGES", "LICENSE", "NOTICE", "README", "Rakefile", "TODO", "friendly_format.gemspec", "lib/friendly_format.rb", "lib/friendly_format/adapter/abstract.rb", "lib/friendly_format/adapter/hpricot_adapter.rb", "lib/friendly_format/adapter/libxml_adapter.rb", "lib/friendly_format/adapter/nokogiri_adapter.rb", "lib/friendly_format/set_common.rb", "lib/friendly_format/set_strict.rb", "lib/friendly_format/version.rb", "test/sample/complex_article.txt", "test/sample/complex_article_result.txt", "test/test_friendly_format.rb"]
|
15
14
|
s.has_rdoc = true
|
16
15
|
s.homepage = %q{http://github.com/godfat/friendly_format}
|
17
|
-
s.rdoc_options = ["--
|
16
|
+
s.rdoc_options = ["--charset=utf-8", "--inline-source", "--line-numbers", "--promiscuous", "--main", "README"]
|
18
17
|
s.require_paths = ["lib"]
|
19
18
|
s.rubyforge_project = %q{ludy}
|
20
19
|
s.rubygems_version = %q{1.3.1}
|
@@ -26,21 +25,18 @@ Gem::Specification.new do |s|
|
|
26
25
|
s.specification_version = 2
|
27
26
|
|
28
27
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
29
|
-
s.add_development_dependency(%q<bones>, [">= 2.2
|
30
|
-
s.add_development_dependency(%q<minitest>, [">= 1.3"])
|
28
|
+
s.add_development_dependency(%q<bones>, [">= 2.4.2"])
|
31
29
|
s.add_development_dependency(%q<hpricot>, [">= 0.6"])
|
32
30
|
s.add_development_dependency(%q<nokogiri>, [">= 1.1"])
|
33
31
|
s.add_development_dependency(%q<libxml-ruby>, [">= 0.9"])
|
34
32
|
else
|
35
|
-
s.add_dependency(%q<bones>, [">= 2.2
|
36
|
-
s.add_dependency(%q<minitest>, [">= 1.3"])
|
33
|
+
s.add_dependency(%q<bones>, [">= 2.4.2"])
|
37
34
|
s.add_dependency(%q<hpricot>, [">= 0.6"])
|
38
35
|
s.add_dependency(%q<nokogiri>, [">= 1.1"])
|
39
36
|
s.add_dependency(%q<libxml-ruby>, [">= 0.9"])
|
40
37
|
end
|
41
38
|
else
|
42
|
-
s.add_dependency(%q<bones>, [">= 2.2
|
43
|
-
s.add_dependency(%q<minitest>, [">= 1.3"])
|
39
|
+
s.add_dependency(%q<bones>, [">= 2.4.2"])
|
44
40
|
s.add_dependency(%q<hpricot>, [">= 0.6"])
|
45
41
|
s.add_dependency(%q<nokogiri>, [">= 1.1"])
|
46
42
|
s.add_dependency(%q<libxml-ruby>, [">= 0.9"])
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
module FriendlyFormat
|
3
|
+
module Abstract
|
4
|
+
|
5
|
+
def method_name node
|
6
|
+
# discard body
|
7
|
+
node.children.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_xhtml node
|
11
|
+
node.to_xhtml
|
12
|
+
end
|
13
|
+
|
14
|
+
def content node
|
15
|
+
node.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
def element? node
|
19
|
+
node.element?
|
20
|
+
end
|
21
|
+
|
22
|
+
def text? node
|
23
|
+
node.text?
|
24
|
+
end
|
25
|
+
|
26
|
+
def empty? node
|
27
|
+
node.children.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
end # of Abstract
|
31
|
+
end # of FriendlyFormat
|
@@ -9,10 +9,14 @@ module FriendlyFormat
|
|
9
9
|
Hpricot.parse(html)
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
12
|
+
def to_xhtml node
|
13
13
|
node.to_html
|
14
14
|
end
|
15
15
|
|
16
|
+
def content node
|
17
|
+
node.content
|
18
|
+
end
|
19
|
+
|
16
20
|
def element? node
|
17
21
|
node.kind_of?(Hpricot::Elem)
|
18
22
|
end
|
@@ -25,18 +29,6 @@ module FriendlyFormat
|
|
25
29
|
node.empty?
|
26
30
|
end
|
27
31
|
|
28
|
-
def tag_name node
|
29
|
-
node.stag.name
|
30
|
-
end
|
31
|
-
|
32
|
-
def tag_begin node
|
33
|
-
node.stag.inspect
|
34
|
-
end
|
35
|
-
|
36
|
-
def tag_end node
|
37
|
-
(node.etag || Hpricot::ETag.new(node.stag.name)).inspect
|
38
|
-
end
|
39
|
-
|
40
32
|
end # of class method for HpricotAdapter
|
41
33
|
end # of HpricotAdapter
|
42
34
|
end # of FriendlyFormat
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
require 'friendly_format/adapter/abstract'
|
3
|
+
require 'libxml'
|
4
|
+
|
5
|
+
module FriendlyFormat
|
6
|
+
class LibxmlAdapter
|
7
|
+
extend Abstract
|
8
|
+
|
9
|
+
def self.parse html
|
10
|
+
parser = LibXML::XML::HTMLParser.string(
|
11
|
+
"<zzz>#{html}</zzz>",
|
12
|
+
:options => LibXML::XML::HTMLParser::Options::RECOVER)
|
13
|
+
|
14
|
+
# root is html, children is [body], first is body
|
15
|
+
# same as nokogiri
|
16
|
+
# drop zzz with .children.first since it would wrap a tag p for the article
|
17
|
+
parser.parse.root.children.first.children.first
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.to_xhtml node
|
21
|
+
node.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
end # of LibxmlAdapter
|
25
|
+
end # of FriendlyFormat
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
require 'friendly_format/adapter/abstract'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
module FriendlyFormat
|
6
|
+
class NokogiriAdapter
|
7
|
+
extend Abstract
|
8
|
+
|
9
|
+
def self.parse html
|
10
|
+
# root is html, children is [body], first is body
|
11
|
+
# same as libxml
|
12
|
+
# drop zzz with .children.first since it would wrap a tag p for the article
|
13
|
+
Nokogiri::HTML.parse(
|
14
|
+
"<zzz>#{html}</zzz>",
|
15
|
+
nil, # url?
|
16
|
+
html.respond_to?(:encoding) ? html.encoding.name : 'utf-8'
|
17
|
+
).root.children.first.children.first
|
18
|
+
end
|
19
|
+
|
20
|
+
end # of NokogiriAdapter
|
21
|
+
end # of FriendlyFormat
|
@@ -6,11 +6,11 @@ module FriendlyFormat
|
|
6
6
|
# a few people have permission to post or edit.
|
7
7
|
class SetCommon < Set
|
8
8
|
def initialize
|
9
|
-
super([
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
super(%w[ a area b big blockquote br
|
10
|
+
center cite code del div em
|
11
|
+
font h1 h2 h3 h4 h5 h6 hr
|
12
|
+
i img li map object ol p
|
13
|
+
pre small span strong u ul ])
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
data/lib/friendly_format.rb
CHANGED
@@ -5,14 +5,22 @@ require 'friendly_format/set_strict'
|
|
5
5
|
|
6
6
|
# 2008-05-09 godfat
|
7
7
|
module FriendlyFormat
|
8
|
-
autoload(:LibxmlAdapter, 'friendly_format/
|
9
|
-
autoload(:HpricotAdapter, 'friendly_format/
|
10
|
-
autoload(:NokogiriAdapter, 'friendly_format/
|
8
|
+
autoload(:LibxmlAdapter, 'friendly_format/adapter/libxml_adapter')
|
9
|
+
autoload(:HpricotAdapter, 'friendly_format/adapter/hpricot_adapter')
|
10
|
+
autoload(:NokogiriAdapter, 'friendly_format/adapter/nokogiri_adapter')
|
11
11
|
|
12
12
|
class << self
|
13
13
|
attr_writer(:adapter)
|
14
14
|
def adapter
|
15
|
-
@adapter ||=
|
15
|
+
@adapter ||= begin
|
16
|
+
HpricotAdapter
|
17
|
+
rescue LoadError
|
18
|
+
begin
|
19
|
+
NokogiriAdapter
|
20
|
+
rescue LoadError
|
21
|
+
LibxmlAdapter
|
22
|
+
end
|
23
|
+
end
|
16
24
|
end
|
17
25
|
end
|
18
26
|
|
@@ -22,15 +30,20 @@ module FriendlyFormat
|
|
22
30
|
# default was no tags at all, all tags would be escaped.
|
23
31
|
# it uses Hpricot to parse input.
|
24
32
|
def format_article html, *args
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
33
|
+
return html if html.strip == ''
|
34
|
+
|
35
|
+
FriendlyFormat.force_encoding(
|
36
|
+
FriendlyFormat.format_article_entrance(html,
|
37
|
+
args.inject(Set.new){ |allowed_tags, arg|
|
38
|
+
case arg
|
39
|
+
when String; allowed_tags << arg
|
40
|
+
when Symbol; allowed_tags << arg.to_s
|
41
|
+
when Set; allowed_tags += Set.new(arg.map{|a|a.to_s})
|
42
|
+
else; raise(TypeError.new("expected String|Symbol|Set, got #{arg.class}"))
|
43
|
+
end
|
44
|
+
allowed_tags
|
45
|
+
}),
|
46
|
+
html)
|
34
47
|
end
|
35
48
|
|
36
49
|
# automaticly add "a href" tag on text starts from
|
@@ -38,8 +51,12 @@ module FriendlyFormat
|
|
38
51
|
# regexp translated from drupal to find where's the target.
|
39
52
|
# it uses simplified regexp to do the task. see format_url.
|
40
53
|
def format_autolink html, attrs = {}
|
41
|
-
|
42
|
-
|
54
|
+
return html if html.strip == ''
|
55
|
+
|
56
|
+
FriendlyFormat.force_encoding(
|
57
|
+
FriendlyFormat.format_autolink_rec(
|
58
|
+
FriendlyFormat.adapter.parse(html), attrs),
|
59
|
+
html)
|
43
60
|
end
|
44
61
|
|
45
62
|
# translated from drupal-6.2/modules/filter/filter.module
|
@@ -104,13 +121,12 @@ module FriendlyFormat
|
|
104
121
|
text.gsub(
|
105
122
|
%r{((http://|https://|ftp://|mailto:|smb://|afp://|file://|gopher://|news://|ssl://|sslv2://|sslv3://|tls://|tcp://|udp://|www\.)([a-zA-Z0-9@:%_+*~#?&=.,/;-]*[a-zA-Z0-9@:%_+*~#&=/;-]))([.,?!]*?)}i){ |match|
|
106
123
|
url = $1 # is there any other way to get this variable?
|
107
|
-
|
108
124
|
caption = trim(url)
|
109
|
-
|
125
|
+
html_attrs = attrs.map{ |k,v| " #{k}=\"#{v}\""}.join
|
110
126
|
|
111
127
|
# Match www domains/addresses.
|
112
128
|
url = "http://#{url}" unless url =~ %r{^http://}
|
113
|
-
"<a href=\"#{url}\" title=\"#{url}\"#{
|
129
|
+
"<a href=\"#{url}\" title=\"#{url}\"#{html_attrs}>#{caption}</a>"
|
114
130
|
# Match e-mail addresses.
|
115
131
|
}.gsub( %r{([A-Za-z0-9._-]+@[A-Za-z0-9._+-]+\.[A-Za-z]{2,4})([.,?!]*?)}i,
|
116
132
|
'<a href="mailto:\1">\1</a>')
|
@@ -118,45 +134,46 @@ module FriendlyFormat
|
|
118
134
|
|
119
135
|
# perhaps we should escape all inside code instead of pre?
|
120
136
|
# @api private
|
121
|
-
def
|
122
|
-
return html unless allowed_tags.member?
|
137
|
+
def escape_ltgt_inside_pre html, allowed_tags
|
138
|
+
return html unless allowed_tags.member?('pre')
|
123
139
|
# don't bother nested pre, because we escape all tags in pre
|
124
140
|
html = html + '</pre>' unless html =~ %r{</pre>}i
|
125
141
|
html.gsub(%r{<pre>(.*)</pre>}mi){
|
126
142
|
# stop escaping for '>' because drupal's url filter would make > into url...
|
127
143
|
# is there any other way to get matched group?
|
128
|
-
"<pre>#{
|
144
|
+
"<pre>#{escape_ltgt($1)}</pre>"
|
129
145
|
}
|
130
146
|
end
|
131
147
|
|
132
148
|
# @api private
|
133
149
|
def format_autolink_rec elem, attrs = {}
|
134
|
-
elem.children.map{ |
|
135
|
-
if adapter.text?(
|
136
|
-
format_url(
|
150
|
+
elem.children.map{ |e|
|
151
|
+
if adapter.text?(e)
|
152
|
+
format_url(e.content, attrs)
|
137
153
|
|
138
|
-
elsif adapter.element?(
|
139
|
-
if adapter.empty?(
|
140
|
-
|
154
|
+
elsif adapter.element?(e)
|
155
|
+
if adapter.empty?(e)
|
156
|
+
adapter.to_xhtml(e)
|
141
157
|
else
|
142
|
-
|
143
|
-
format_autolink_rec(
|
144
|
-
|
158
|
+
"<#{e.name}>" +
|
159
|
+
format_autolink_rec(e, attrs) +
|
160
|
+
"</#{e.name}>"
|
145
161
|
end
|
146
162
|
|
147
163
|
else
|
148
|
-
|
164
|
+
e
|
149
165
|
|
150
166
|
end
|
151
167
|
|
152
|
-
}.
|
168
|
+
}.join
|
153
169
|
end
|
154
170
|
|
155
171
|
# recursion entrance
|
156
172
|
# @api private
|
157
173
|
def format_article_entrance html, allowed_tags = Set.new
|
158
|
-
format_article_rec(
|
159
|
-
|
174
|
+
format_article_rec(
|
175
|
+
adapter.parse(escape_ltgt_inside_pre(html, allowed_tags)),
|
176
|
+
allowed_tags)
|
160
177
|
end
|
161
178
|
|
162
179
|
# recursion
|
@@ -165,38 +182,33 @@ module FriendlyFormat
|
|
165
182
|
elem.children.map{ |e|
|
166
183
|
if adapter.text?(e)
|
167
184
|
if no_format_newline
|
168
|
-
format_url(
|
185
|
+
format_url(adapter.content(e))
|
169
186
|
else
|
170
|
-
format_newline(format_url(
|
187
|
+
format_newline(format_url(adapter.content(e)))
|
171
188
|
end
|
172
189
|
|
173
190
|
elsif adapter.element?(e)
|
174
|
-
if allowed_tags.member?(e.name
|
191
|
+
if allowed_tags.member?(e.name)
|
175
192
|
if adapter.empty?(e) || e.name == 'a'
|
176
|
-
e
|
193
|
+
adapter.to_xhtml(e)
|
177
194
|
else
|
178
|
-
|
195
|
+
"<#{e.name}>" +
|
179
196
|
format_article_rec(
|
180
|
-
e, allowed_tags,
|
181
|
-
|
197
|
+
e, allowed_tags, e.name == 'pre') +
|
198
|
+
"</#{e.name}>"
|
182
199
|
end
|
183
200
|
else
|
184
201
|
if adapter.empty?(e)
|
185
|
-
|
202
|
+
"<#{e.name}>"
|
186
203
|
else
|
187
|
-
|
204
|
+
"<#{e.name}>" +
|
188
205
|
format_article_rec(e, allowed_tags) +
|
189
|
-
|
206
|
+
"</#{e.name}>"
|
190
207
|
end
|
191
208
|
end
|
192
209
|
|
193
210
|
end
|
194
|
-
}.
|
195
|
-
end
|
196
|
-
|
197
|
-
# @api private
|
198
|
-
def escape_amp text
|
199
|
-
text.gsub('&', '&')
|
211
|
+
}.join
|
200
212
|
end
|
201
213
|
|
202
214
|
# i cannot find a way to escape both lt and gt,
|
@@ -204,8 +216,18 @@ module FriendlyFormat
|
|
204
216
|
# would treat complex lt and gt structure to be a tag
|
205
217
|
# wraping content.
|
206
218
|
# @api private
|
207
|
-
def
|
208
|
-
text.gsub('<', '<')
|
219
|
+
def escape_ltgt text
|
220
|
+
text.gsub('<', '<').gsub('>', '>')
|
221
|
+
end
|
222
|
+
|
223
|
+
# force encoding for ruby 1.9
|
224
|
+
# @api private
|
225
|
+
def force_encoding output, input
|
226
|
+
if output.respond_to?(:force_encoding)
|
227
|
+
output.force_encoding(input.encoding)
|
228
|
+
else
|
229
|
+
output
|
230
|
+
end
|
209
231
|
end
|
210
232
|
|
211
233
|
end
|
@@ -2,93 +2,93 @@
|
|
2
2
|
標題 Re: [PSC] variants timer
|
3
3
|
時間 2008/03/04 Tue 00:34:54
|
4
4
|
<a href="http://phpbb.godfat.org/viewtopic.php?t=873" title="http://phpbb.godfat.org/viewtopic.php?t=873">http://phpbb.godfat.org/viewtopic.php?t=873</a>
|
5
|
-
<a href="<a href="http://phpbb.godfat.org/viewtopic.php?t=873" title="http://phpbb.godfat.org/viewtopic.php?t=873">http://phpbb.godfat.org/viewtopic.php?t=873</a>"
|
6
|
-
測試</a
|
7
|
-
<a href="<a href="http://phpbb.godfat.org/viewtopic.php?t=873" title="http://phpbb.godfat.org/viewtopic.php?t=873">http://phpbb.godfat.org/viewtopic.php?t=873</a>"
|
8
|
-
<img src="<a href="http://phpbb.godfat.org/templates/subSilver/images/logo_phpBB.gif" title="http://phpbb.godfat.org/templates/subSilver/images/logo_phpBB.gif">http://phpbb.godfat.org/templates/subSilver/images/logo_phpBB.gif</a>"
|
5
|
+
<a href="<a href="http://phpbb.godfat.org/viewtopic.php?t=873" title="http://phpbb.godfat.org/viewtopic.php?t=873">http://phpbb.godfat.org/viewtopic.php?t=873</a>">
|
6
|
+
測試</a>
|
7
|
+
<a href="<a href="http://phpbb.godfat.org/viewtopic.php?t=873" title="http://phpbb.godfat.org/viewtopic.php?t=873">http://phpbb.godfat.org/viewtopic.php?t=873</a>">
|
8
|
+
<img src="<a href="http://phpbb.godfat.org/templates/subSilver/images/logo_phpBB.gif" title="http://phpbb.godfat.org/templates/subSilver/images/logo_phpBB.gif">http://phpbb.godfat.org/templates/subSilver/images/logo_phpBB.gif</a>"/></a>
|
9
9
|
※ 引述《godfat (godfat 真常)》之銘言:
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
以上 A, B, C 是指 timer_subscriber_list<A
|
20
|
-
|
21
|
-
這個東西會需要從 T
|
10
|
+
> 3. tuple + traits, 也就是一堆 template 技巧了
|
11
|
+
> class Dispatcher{
|
12
|
+
> template <class T>
|
13
|
+
> void sub(shared_ptr<T> p){
|
14
|
+
> get_tuple_data_field_by_type<T>(data).push_back(p);
|
15
|
+
> }
|
16
|
+
> tuple<A, B, C> data;
|
17
|
+
> };
|
18
|
+
|
19
|
+
以上 A, B, C 是指 timer_subscriber_list<A>, etc.
|
20
|
+
|
21
|
+
這個東西會需要從 T => tuple index 的 mapping
|
22
22
|
現在這部份做完了...........(template 沒忘太多啊哈哈)
|
23
23
|
|
24
|
-
#include <tr1/tuple
|
25
|
-
#include <tr1/type_traits
|
26
|
-
#include <iostream
|
24
|
+
#include <tr1/tuple>
|
25
|
+
#include <tr1/type_traits>
|
26
|
+
#include <iostream>
|
27
27
|
|
28
28
|
using namespace std::tr1;
|
29
29
|
|
30
30
|
// 拿來判斷兩個整數是否相同,這是為了檢查有沒有爆表
|
31
|
-
// 像是 tuple_element<3, tuple<int,int,int
|
31
|
+
// 像是 tuple_element<3, tuple<int,int,int> >::type
|
32
32
|
// 這樣就是爆表,因為這 tuple 沒這麼大
|
33
|
-
template <bool
|
34
|
-
template <
|
33
|
+
template <bool> struct is_equal_type { typedef true_type type; };
|
34
|
+
template <> struct is_equal_type<false>{ typedef false_type type; };
|
35
35
|
|
36
|
-
// 定義相等的話,is_equal<1,1
|
37
|
-
// is_equal<1,2
|
36
|
+
// 定義相等的話,is_equal<1,1>::value 會是 1
|
37
|
+
// is_equal<1,2>::value 會是 0
|
38
38
|
// ::type 會是 true_type/false_type (from tr1)
|
39
|
-
template <int Lhs, int Rhs
|
39
|
+
template <int Lhs, int Rhs> struct is_equal{
|
40
40
|
enum{ value = Lhs == Rhs };
|
41
|
-
typedef typename is_equal_type<value
|
41
|
+
typedef typename is_equal_type<value>::type type;
|
42
42
|
};
|
43
43
|
|
44
|
-
template <class T, class Tuple, int Index
|
44
|
+
template <class T, class Tuple, int Index> struct type_index_imp;
|
45
45
|
|
46
46
|
// 如果跑到這裡,表示爆表了,在我的 g++4.3 上會顯示:
|
47
47
|
// tuple.cpp:20: error: ‘type_not_found’ is not a member of "T"
|
48
|
-
template <class T, class Tuple, int Index, class Bool
|
48
|
+
template <class T, class Tuple, int Index, class Bool>
|
49
49
|
struct type_index_check{
|
50
50
|
enum{ value = T::type_not_found };
|
51
51
|
};
|
52
52
|
|
53
53
|
// 沒有爆表就繼續找吧
|
54
|
-
template <class T, class Tuple, int Index
|
55
|
-
struct type_index_check<T, Tuple, Index, false_type
|
56
|
-
enum{ value = type_index_imp<T, Tuple, Index+1
|
54
|
+
template <class T, class Tuple, int Index>
|
55
|
+
struct type_index_check<T, Tuple, Index, false_type>{
|
56
|
+
enum{ value = type_index_imp<T, Tuple, Index+1>::value };
|
57
57
|
};
|
58
58
|
|
59
59
|
// 找到了!
|
60
|
-
template <class T, class Tuple, int Index, class Bool
|
60
|
+
template <class T, class Tuple, int Index, class Bool>
|
61
61
|
struct type_index_if{
|
62
62
|
enum{ value = Index }; // found, stop recursion
|
63
63
|
};
|
64
64
|
|
65
65
|
// 不直接呼叫 imp, 呼叫 check 檢查是否爆表
|
66
|
-
template <class T, class Tuple, int Index
|
67
|
-
struct type_index_if<T, Tuple, Index, false_type
|
66
|
+
template <class T, class Tuple, int Index>
|
67
|
+
struct type_index_if<T, Tuple, Index, false_type>{
|
68
68
|
enum{ value = type_index_check<T, Tuple, Index,
|
69
|
-
typename is_equal<Index+1, tuple_size<Tuple
|
69
|
+
typename is_equal<Index+1, tuple_size<Tuple>::value>::type>::value };
|
70
70
|
};
|
71
71
|
|
72
72
|
// 檢查兩個型別是否相同
|
73
|
-
template <class T, class Tuple, int Index
|
73
|
+
template <class T, class Tuple, int Index>
|
74
74
|
struct type_index_imp{
|
75
75
|
enum{ value = type_index_if<T, Tuple, Index,
|
76
|
-
typename is_same<T, typename tuple_element<Index, Tuple
|
76
|
+
typename is_same<T, typename tuple_element<Index, Tuple>::type>::type>::value };
|
77
77
|
};
|
78
78
|
|
79
79
|
// simple wrapper
|
80
|
-
template <class T, class Tuple
|
80
|
+
template <class T, class Tuple>
|
81
81
|
struct type_index{
|
82
|
-
enum{ value = type_index_imp<T, Tuple, 0
|
82
|
+
enum{ value = type_index_imp<T, Tuple, 0>::value };
|
83
83
|
};
|
84
84
|
|
85
85
|
int main(){
|
86
|
-
typedef tuple<int, char, void
|
87
|
-
std::cout << type_index<int, test_t
|
88
|
-
std::cout << type_index<char, test_t
|
89
|
-
std::cout << type_index<void, test_t
|
90
|
-
std::cout << tuple_size<test_t
|
91
|
-
// std::cout << type_index<int*, test_t
|
86
|
+
typedef tuple<int, char, void> test_t;
|
87
|
+
std::cout << type_index<int, test_t>::value << std::endl;
|
88
|
+
std::cout << type_index<char, test_t>::value << std::endl;
|
89
|
+
std::cout << type_index<void, test_t>::value << std::endl;
|
90
|
+
std::cout << tuple_size<test_t>::value << std::endl;
|
91
|
+
// std::cout << type_index<int*, test_t>::value << std::endl;
|
92
92
|
}
|
93
93
|
|
94
94
|
輸出:
|
@@ -1,15 +1,19 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
|
-
require 'minitest/unit'
|
5
|
-
MiniTest::Unit.autorun
|
6
4
|
|
7
|
-
|
5
|
+
TestCase = begin
|
6
|
+
require 'minitest/unit'
|
7
|
+
MiniTest::Unit.autorun
|
8
|
+
MiniTest::Unit::TestCase
|
9
|
+
rescue LoadError
|
10
|
+
require 'test/unit'
|
11
|
+
Test::Unit::TestCase
|
12
|
+
end
|
8
13
|
|
9
|
-
|
14
|
+
require 'friendly_format'
|
10
15
|
|
11
|
-
|
12
|
-
class TestFriendlyFormat < MiniTest::Unit::TestCase
|
16
|
+
module TestCases
|
13
17
|
include FriendlyFormat
|
14
18
|
|
15
19
|
def test_article
|
@@ -39,7 +43,9 @@ OpenGL, 還有一些 web cgi 之類的東西也有。
|
|
39
43
|
|
40
44
|
現在切入正是時機啊... XD'
|
41
45
|
|
42
|
-
|
46
|
+
s = format_autolink(str)
|
47
|
+
|
48
|
+
assert(
|
43
49
|
' <a href="http://friends.roodo.com/forum/viewTopic/10170" title="http://friends.roodo.com/forum/viewTopic/10170">http://friends.roodo.com/forum/viewTopic/10170</a>
|
44
50
|
用 Haskell 寫成的名軟體?
|
45
51
|
|
@@ -63,17 +69,19 @@ svn 其實也差不多是要慢慢式微了...
|
|
63
69
|
很多知名 library 都有 haskell binding 了,wxWidgets,
|
64
70
|
OpenGL, 還有一些 web cgi 之類的東西也有。
|
65
71
|
|
66
|
-
現在切入正是時機啊... XD'
|
67
|
-
assert_equal
|
72
|
+
現在切入正是時機啊... XD' == s)
|
73
|
+
assert_equal(s, format_autolink_regexp(str))
|
68
74
|
end
|
69
75
|
def test_persent
|
70
76
|
str =
|
71
77
|
'XDDDD
|
72
78
|
http://www.amazon.co.jp/%E3%80%8C%E7%84%94~%E3%83%9B%E3%83%A0%E3%83%A9%E3%80%8D~Ar-tonelico2-hymmnos-concert-Side-%E7%B4%85~/dp/B000VKZL30/ref=pd_sbs_sw_img_2 orz'
|
73
79
|
|
74
|
-
|
80
|
+
s = format_autolink(str)
|
81
|
+
|
82
|
+
assert_equal(
|
75
83
|
'XDDDD
|
76
|
-
<a href="http://www.amazon.co.jp/%E3%80%8C%E7%84%94~%E3%83%9B%E3%83%A0%E3%83%A9%E3%80%8D~Ar-tonelico2-hymmnos-concert-Side-%E7%B4%85~/dp/B000VKZL30/ref=pd_sbs_sw_img_2" title="http://www.amazon.co.jp/%E3%80%8C%E7%84%94~%E3%83%9B%E3%83%A0%E3%83%A9%E3%80%8D~Ar-tonelico2-hymmnos-concert-Side-%E7%B4%85~/dp/B000VKZL30/ref=pd_sbs_sw_img_2">http://www.amazon.co.jp/%E3%80%8C%E7%84%94~%E3%83%9B%E3%83%A0%E3%83%A9%E...</a> orz', s
|
84
|
+
<a href="http://www.amazon.co.jp/%E3%80%8C%E7%84%94~%E3%83%9B%E3%83%A0%E3%83%A9%E3%80%8D~Ar-tonelico2-hymmnos-concert-Side-%E7%B4%85~/dp/B000VKZL30/ref=pd_sbs_sw_img_2" title="http://www.amazon.co.jp/%E3%80%8C%E7%84%94~%E3%83%9B%E3%83%A0%E3%83%A9%E3%80%8D~Ar-tonelico2-hymmnos-concert-Side-%E7%B4%85~/dp/B000VKZL30/ref=pd_sbs_sw_img_2">http://www.amazon.co.jp/%E3%80%8C%E7%84%94~%E3%83%9B%E3%83%A0%E3%83%A9%E...</a> orz', s)
|
77
85
|
assert_equal s, format_autolink_regexp(str)
|
78
86
|
end
|
79
87
|
def test_img_src
|
@@ -83,9 +91,21 @@ http://www.amazon.co.jp/%E3%80%8C%E7%84%94~%E3%83%9B%E3%83%A0%E3%83%A9%E3%80%8D~
|
|
83
91
|
|
84
92
|
2007年12月14日
|
85
93
|
'
|
86
|
-
|
87
|
-
|
94
|
+
libxml =
|
95
|
+
'Thirst for Knowledge
|
96
|
+
<img src="http://friends.roodo.com/images/diary_photos_large/15386/MjMyNjYtdGhpcnN0X2Zvcl9rbm93bGVkZ2U=.jpg"/>
|
97
|
+
|
98
|
+
2007年12月14日
|
99
|
+
'
|
100
|
+
s = format_autolink(str)
|
101
|
+
if FriendlyFormat.adapter == FriendlyFormat::LibxmlAdapter
|
102
|
+
assert_equal(libxml, s)
|
103
|
+
else
|
104
|
+
assert_equal(str, s)
|
105
|
+
end
|
106
|
+
assert_equal(str, format_autolink_regexp(str))
|
88
107
|
end
|
108
|
+
|
89
109
|
def test_wikipedia_persent
|
90
110
|
str = 'http://en.wikipedia.org/wiki/Haskell_%28programming_language%29'
|
91
111
|
assert_equal \
|
@@ -113,14 +133,20 @@ http://www.amazon.co.jp/%E3%80%8C%E7%84%94~%E3%83%9B%E3%83%A0%E3%83%A9%E3%80%8D~
|
|
113
133
|
def test_escape_html_and_correct_html
|
114
134
|
str = 'test<p>if missing end of p'
|
115
135
|
assert_equal 'test<p>if missing end of p</p>', format_article(str, :p)
|
116
|
-
assert_equal 'test<p
|
136
|
+
assert_equal 'test<p>if missing end of p</p>', format_article(str, :a)
|
137
|
+
|
117
138
|
str = '<pre>asdasd<a>orz'
|
118
|
-
assert_equal '<pre>asdasd<a
|
119
|
-
assert_equal '<pre
|
120
|
-
assert_equal '<pre>asdasd<a
|
139
|
+
assert_equal '<pre>asdasd<a>orz</pre>', format_article(str, :a, :pre)
|
140
|
+
assert_equal '<pre>asdasd<a>orz</a></pre>', format_article(str, :a)
|
141
|
+
assert_equal '<pre>asdasd<a>orz</pre>', format_article(str, :pre)
|
142
|
+
|
121
143
|
str = 'orz<img>asd'
|
122
|
-
|
123
|
-
|
144
|
+
if FriendlyFormat.adapter == FriendlyFormat::LibxmlAdapter
|
145
|
+
assert_equal('orz<img/>asd', format_article(str, :img))
|
146
|
+
else
|
147
|
+
assert_equal('orz<img />asd', format_article(str, :img))
|
148
|
+
end
|
149
|
+
assert_equal 'orz<img>asd', format_article(str)
|
124
150
|
end
|
125
151
|
def test_trim_url
|
126
152
|
str = 'test with http://890123456789012345678901234567890123456789012345678901234567890123456789.com'
|
@@ -129,8 +155,16 @@ http://www.amazon.co.jp/%E3%80%8C%E7%84%94~%E3%83%9B%E3%83%A0%E3%83%A9%E3%80%8D~
|
|
129
155
|
assert_equal s, format_autolink_regexp(str)
|
130
156
|
end
|
131
157
|
def test_escape_html
|
132
|
-
|
133
|
-
|
158
|
+
str = 'a lambda expression is λ x. x+1'
|
159
|
+
libxml = 'a lambda expression is λ x. x+1'
|
160
|
+
result = format_article(str)
|
161
|
+
|
162
|
+
if FriendlyFormat.adapter == FriendlyFormat::HpricotAdapter
|
163
|
+
assert_equal(str, result)
|
164
|
+
else
|
165
|
+
assert_equal(libxml, result)
|
166
|
+
end
|
167
|
+
|
134
168
|
str = 'as you can see, use <img src="asd"/> to use'
|
135
169
|
assert_equal str, format_article(str)
|
136
170
|
end
|
@@ -138,8 +172,8 @@ http://www.amazon.co.jp/%E3%80%8C%E7%84%94~%E3%83%9B%E3%83%A0%E3%83%A9%E3%80%8D~
|
|
138
172
|
result = File.read('test/sample/complex_article_result.txt').chop
|
139
173
|
input = File.read('test/sample/complex_article.txt')
|
140
174
|
|
141
|
-
assert_equal
|
142
|
-
assert_equal
|
175
|
+
assert_equal(result, format_article(input, :pre))
|
176
|
+
assert_equal(result, format_article(input, SetCommon.new))
|
143
177
|
end
|
144
178
|
def test_simple_link
|
145
179
|
s = '今天是我一歲生日 <a href="http://godfat.org/" title="http://godfat.org/">http://godfat.org/</a> 真的嗎?'
|
@@ -162,9 +196,39 @@ compilation mode. 非常驚人的開發速度。
|
|
162
196
|
此外,其中一位開發者,<a href="http://blog.headius.com/">Charles Nutter</a> 也經常參與 <a href="http://www.ruby-forum.com/forum/14">ruby-core</a> 的討論,
|
163
197
|
對於 Ruby 的開發頗有貢獻。'
|
164
198
|
|
165
|
-
expected = '<img src="http://flolac.iis.sinica.edu.tw/lambdawan/sites/default/files/ruby.png.thumb.jpg"
|
199
|
+
expected = '<img style="float: right;" src="http://flolac.iis.sinica.edu.tw/lambdawan/sites/default/files/ruby.png.thumb.jpg" /><br /><a href="http://www.ruby-forum.com/topic/169911">JRuby 1.1.5 Released</a><br /><a href="http://jruby.codehaus.org/">JRuby</a> 是用 Java 寫成的 Ruby interpreter/compiler.<br />原本 JRuby 只是普通的 open source project, 後來因為 <a href="http://www.sun.com/">Sun Microsystem</a>,<br />也就是 Java 的開發公司,看好 JRuby, 於是僱用 JRuby team,<br />full time 開發 JRuby. 後來 JRuby 在各方面都快速大幅成長,<br />尤其效能有了不可思議的大幅提昇,可能是 Sun 有一些撇步沒有公開吧。<br /><br />效能大幅提昇之後,JRuby 開發沒有停緩,接下來是非常大量的相容性提昇。<br />也從原本僅支援 interpret mode 到後來也支援 just in time 與 ahead of time 的<br />compilation mode. 非常驚人的開發速度。<br /><zzz><xd><br />此外,其中一位開發者,<a href="http://blog.headius.com/">Charles Nutter</a> 也經常參與 <a href="http://www.ruby-forum.com/forum/14">ruby-core</a> 的討論,<br />對於 Ruby 的開發頗有貢獻。</xd></zzz>'
|
166
200
|
|
167
|
-
|
201
|
+
# img style after img src
|
202
|
+
expected_18_hpricot = '<img src="http://flolac.iis.sinica.edu.tw/lambdawan/sites/default/files/ruby.png.thumb.jpg" style="float: right;" /><br /><a href="http://www.ruby-forum.com/topic/169911">JRuby 1.1.5 Released</a><br /><a href="http://jruby.codehaus.org/">JRuby</a> 是用 Java 寫成的 Ruby interpreter/compiler.<br />原本 JRuby 只是普通的 open source project, 後來因為 <a href="http://www.sun.com/">Sun Microsystem</a>,<br />也就是 Java 的開發公司,看好 JRuby, 於是僱用 JRuby team,<br />full time 開發 JRuby. 後來 JRuby 在各方面都快速大幅成長,<br />尤其效能有了不可思議的大幅提昇,可能是 Sun 有一些撇步沒有公開吧。<br /><br />效能大幅提昇之後,JRuby 開發沒有停緩,接下來是非常大量的相容性提昇。<br />也從原本僅支援 interpret mode 到後來也支援 just in time 與 ahead of time 的<br />compilation mode. 非常驚人的開發速度。<br /><zzz><xd><br />此外,其中一位開發者,<a href="http://blog.headius.com/">Charles Nutter</a> 也經常參與 <a href="http://www.ruby-forum.com/forum/14">ruby-core</a> 的討論,<br />對於 Ruby 的開發頗有貢獻。</xd></zzz>'
|
168
203
|
|
204
|
+
result = format_article(input, SetCommon.new, :zzz)
|
205
|
+
if RUBY_VERSION =~ /^1\.8/ && FriendlyFormat.adapter == FriendlyFormat::HpricotAdapter
|
206
|
+
assert(result == expected_18_hpricot)
|
207
|
+
else
|
208
|
+
assert(result == expected)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_empty_article
|
213
|
+
assert_equal '', format_article('')
|
214
|
+
assert_equal ' ', format_article(' ')
|
215
|
+
assert_equal 'a', format_article('a')
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_custom_set
|
219
|
+
s = '<z>zzz</z>'
|
220
|
+
assert_equal s, format_article(s, Set.new << :z)
|
169
221
|
end
|
170
222
|
end
|
223
|
+
|
224
|
+
%w[HpricotAdapter NokogiriAdapter LibxmlAdapter].each{ |adapter|
|
225
|
+
eval <<-RUBY
|
226
|
+
class Test#{adapter} < TestCase
|
227
|
+
include TestCases
|
228
|
+
|
229
|
+
def setup
|
230
|
+
FriendlyFormat.adapter = FriendlyFormat::#{adapter}
|
231
|
+
end
|
232
|
+
end
|
233
|
+
RUBY
|
234
|
+
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: godfat-friendly_format
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Lin Jen-Shin (a.k.a. godfat \xE7\x9C\x9F\xE5\xB8\xB8)"
|
@@ -9,29 +9,22 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-04-05 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bones
|
17
|
+
type: :development
|
17
18
|
version_requirement:
|
18
19
|
version_requirements: !ruby/object:Gem::Requirement
|
19
20
|
requirements:
|
20
21
|
- - ">="
|
21
22
|
- !ruby/object:Gem::Version
|
22
|
-
version: 2.2
|
23
|
-
version:
|
24
|
-
- !ruby/object:Gem::Dependency
|
25
|
-
name: minitest
|
26
|
-
version_requirement:
|
27
|
-
version_requirements: !ruby/object:Gem::Requirement
|
28
|
-
requirements:
|
29
|
-
- - ">="
|
30
|
-
- !ruby/object:Gem::Version
|
31
|
-
version: "1.3"
|
23
|
+
version: 2.4.2
|
32
24
|
version:
|
33
25
|
- !ruby/object:Gem::Dependency
|
34
26
|
name: hpricot
|
27
|
+
type: :development
|
35
28
|
version_requirement:
|
36
29
|
version_requirements: !ruby/object:Gem::Requirement
|
37
30
|
requirements:
|
@@ -41,6 +34,7 @@ dependencies:
|
|
41
34
|
version:
|
42
35
|
- !ruby/object:Gem::Dependency
|
43
36
|
name: nokogiri
|
37
|
+
type: :development
|
44
38
|
version_requirement:
|
45
39
|
version_requirements: !ruby/object:Gem::Requirement
|
46
40
|
requirements:
|
@@ -50,6 +44,7 @@ dependencies:
|
|
50
44
|
version:
|
51
45
|
- !ruby/object:Gem::Dependency
|
52
46
|
name: libxml-ruby
|
47
|
+
type: :development
|
53
48
|
version_requirement:
|
54
49
|
version_requirements: !ruby/object:Gem::Requirement
|
55
50
|
requirements:
|
@@ -79,9 +74,10 @@ files:
|
|
79
74
|
- TODO
|
80
75
|
- friendly_format.gemspec
|
81
76
|
- lib/friendly_format.rb
|
82
|
-
- lib/friendly_format/
|
83
|
-
- lib/friendly_format/
|
84
|
-
- lib/friendly_format/
|
77
|
+
- lib/friendly_format/adapter/abstract.rb
|
78
|
+
- lib/friendly_format/adapter/hpricot_adapter.rb
|
79
|
+
- lib/friendly_format/adapter/libxml_adapter.rb
|
80
|
+
- lib/friendly_format/adapter/nokogiri_adapter.rb
|
85
81
|
- lib/friendly_format/set_common.rb
|
86
82
|
- lib/friendly_format/set_strict.rb
|
87
83
|
- lib/friendly_format/version.rb
|
@@ -92,7 +88,6 @@ has_rdoc: true
|
|
92
88
|
homepage: http://github.com/godfat/friendly_format
|
93
89
|
post_install_message:
|
94
90
|
rdoc_options:
|
95
|
-
- --diagram
|
96
91
|
- --charset=utf-8
|
97
92
|
- --inline-source
|
98
93
|
- --line-numbers
|
@@ -1,46 +0,0 @@
|
|
1
|
-
|
2
|
-
module FriendlyFormat
|
3
|
-
class LibxmlAdapter
|
4
|
-
class << self
|
5
|
-
|
6
|
-
def parse html
|
7
|
-
require 'libxml'
|
8
|
-
parser = LibXML::XML::HTMLParser.new
|
9
|
-
parser.string = html
|
10
|
-
# root is html, children is [body], first is body
|
11
|
-
# same as nokogiri
|
12
|
-
parser.parse.root.children.first
|
13
|
-
end
|
14
|
-
|
15
|
-
def to_html node
|
16
|
-
# discard body
|
17
|
-
node.children.to_s
|
18
|
-
end
|
19
|
-
|
20
|
-
def element? node
|
21
|
-
node.element?
|
22
|
-
end
|
23
|
-
|
24
|
-
def text? node
|
25
|
-
node.text?
|
26
|
-
end
|
27
|
-
|
28
|
-
def empty? node
|
29
|
-
node.children.empty?
|
30
|
-
end
|
31
|
-
|
32
|
-
def tag_name node
|
33
|
-
node.name
|
34
|
-
end
|
35
|
-
|
36
|
-
def tag_begin node
|
37
|
-
"<#{node.name}#{node.attributes.to_h}>"
|
38
|
-
end
|
39
|
-
|
40
|
-
def tag_end node
|
41
|
-
empty?(node) ? "<#{node.name}/>" : "</#{node.name}>"
|
42
|
-
end
|
43
|
-
|
44
|
-
end # of class method for LibxmlAdapter
|
45
|
-
end # of LibxmlAdapter
|
46
|
-
end # of FriendlyFormat
|
@@ -1,31 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'friendly_format/adapters/libxml_adapter'
|
3
|
-
require 'nokogiri'
|
4
|
-
|
5
|
-
module FriendlyFormat
|
6
|
-
class NokogiriAdapter < LibxmlAdapter
|
7
|
-
class << self
|
8
|
-
|
9
|
-
def parse html
|
10
|
-
# root is html, children is [body], first is body
|
11
|
-
# same as libxml
|
12
|
-
Nokogiri::HTML.parse(html).root.children.first
|
13
|
-
end
|
14
|
-
|
15
|
-
def element? node
|
16
|
-
node.kind_of?(Nokogiri::XML::Element)
|
17
|
-
end
|
18
|
-
|
19
|
-
def text? node
|
20
|
-
node.kind_of?(Nokogiri::XML::Text)
|
21
|
-
end
|
22
|
-
|
23
|
-
def tag_begin node
|
24
|
-
attrs = node.attributes.map{ |key_value| key_value.join('="') + '"' }.join(' ')
|
25
|
-
attrs = ' ' + attrs if attrs != ''
|
26
|
-
"<#{node.name}#{attrs}>"
|
27
|
-
end
|
28
|
-
|
29
|
-
end # of class method for NokogiriAdapter
|
30
|
-
end # of NokogiriAdapter
|
31
|
-
end # of FriendlyFormat
|