simple_format 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'simple_format/version'
3
+ require 'simple_format/emoji'
4
+ require 'simple_format/auto_link'
5
+ require 'sanitize' unless defined?(::Sanitize)
6
+
7
+ module SimpleFormat
8
+ extend self
9
+
10
+ def h(string, size=64)
11
+ return string unless string
12
+ string = emoji.replace_emoji_with_images(string, size)
13
+ string = auto_link(string)
14
+ string = clean(string)
15
+ end
16
+
17
+ def replace_emoji_with_images(string, size=64)
18
+ emoji.replace_emoji_with_images(string, size)
19
+ end
20
+
21
+ def clean(html, options = {})
22
+ options = { elements: sanitized_allowed_tags, attributes: { all: sanitized_allowed_attributes } } if options.empty?
23
+ Sanitize.clean(html, options)
24
+ end
25
+
26
+ def emoji
27
+ @emoji ||= Emoji.new
28
+ end
29
+
30
+ private
31
+
32
+ def sanitized_allowed_tags
33
+ ['a', 'p', 'br', 'img', 'abbr', 'mark', 'm', 'fieldset', 'legend', 'label', 'summary', 'details', 'address', 'map', 'area', 'td', 'tr', 'th', 'thead', 'tbody', 'tfoot', 'caption', 'table', 'h4', 'h5', 'h6', 'hr', 'span', 'em', 'dl', 'dt', 'dd', 'b', 'del', 'ins', 'small', 'pre', 'blockquote', 'strong', 'audio', 'video', 'source', 'ul', 'ol', 'li', 'i', 'embed', 'sub', 'sup']
34
+ end
35
+
36
+ def sanitized_allowed_attributes
37
+ ['shape', 'coords', 'target', 'href', 'muted', 'volume', 'name', 'class', 'title', 'border', 'poster', 'loop', 'autoplay', 'allowfullscreen', 'fullscreen', 'align' , 'quality', 'allowscriptaccess', 'wmode', 'flashvars', 'webkit-playsinline', 'x-webkit-airplay', 'data-original', 'src', 'controls', 'preload', 'type', 'width', 'height', 'size', 'alt']
38
+ end
39
+
40
+ end
@@ -0,0 +1,94 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module SimpleFormat
4
+ extend self
5
+
6
+ def auto_link(text, *args, &block) #link = :all, html = {}, &block)
7
+ return text unless text
8
+
9
+ options = {}
10
+ unless args.empty?
11
+ options[:link] = args[0] || :all
12
+ end
13
+ options.merge!(:link => :all)
14
+ # 转换回行
15
+ text = nl2br(text).to_str
16
+ # 根据类型生成链接
17
+ case options[:link].to_sym
18
+ when :all then auto_link_email_addresses(auto_link_urls(text, &block), &block)
19
+ when :email_addresses then auto_link_email_addresses(text, &block)
20
+ when :urls then auto_link_urls(text, &block)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def nl2br(string)
27
+ if string
28
+ string.gsub("\n\r","<br />").gsub("\r", "").gsub("\n", "<br />")
29
+ end
30
+ end
31
+
32
+ AUTO_LINK_RE = %r{
33
+ (?: ((?:ed2k|ftp|http|https|irc|mailto|news|gopher|nntp|telnet|webcal|xmpp|callto|feed|svn|urn|aim|rsync|tag|ssh|sftp|rtsp|afs|file):)// | www\. )
34
+ [^\s<]+
35
+ }x
36
+
37
+ # regexps for determining context, used high-volume
38
+ AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
39
+
40
+ AUTO_EMAIL_RE = /[\w.!#\$%+-]+@[\w-]+(?:\.[\w-]+)+/
41
+
42
+ BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
43
+
44
+ WORD_PATTERN = RUBY_VERSION < '1.9' ? '\w' : '\p{Word}'
45
+
46
+ # Turns all urls into clickable links. If a block is given, each url
47
+ # is yielded and the result is used as the link text.
48
+ def auto_link_urls(text)
49
+
50
+ text.gsub(AUTO_LINK_RE) do
51
+ scheme, href = $1, $&
52
+ punctuation = []
53
+
54
+ if auto_linked?($`, $')
55
+ # do not change string; URL is already linked
56
+ href
57
+ else
58
+ # don't include trailing punctuation character as part of the URL
59
+ while href.sub!(/[^#{WORD_PATTERN}\/-]$/, '')
60
+ punctuation.push $&
61
+ if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
62
+ href << punctuation.pop
63
+ break
64
+ end
65
+ end
66
+
67
+ link_text = block_given?? yield(href) : href
68
+ href = 'http://' + href unless scheme
69
+
70
+ "<a href='#{href}' target='_blank'>#{link_text}</a>" + punctuation.reverse.join('')
71
+ end
72
+ end
73
+ end
74
+
75
+ # Turns all email addresses into clickable links. If a block is given,
76
+ # each email is yielded and the result is used as the link text.
77
+ def auto_link_email_addresses(text)
78
+ text.gsub(AUTO_EMAIL_RE) do
79
+ text = $&
80
+ if auto_linked?($`, $')
81
+ text
82
+ else
83
+ display_text = (block_given?) ? yield(text) : text
84
+ # mail_to text, display_text
85
+ "<a href='mailto:#{text}'>#{display_text}</a>"
86
+ end
87
+ end
88
+ end
89
+
90
+ # Detects already linked context or position in the middle of a tag
91
+ def auto_linked?(left, right)
92
+ (left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or (left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
93
+ end
94
+ end
@@ -0,0 +1,112 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'multi_json' unless defined?(::MultiJson)
3
+
4
+ module SimpleFormat
5
+ class Emoji
6
+ def initialize(mapping=nil)
7
+ mapping ||= begin
8
+ emoji_json = File.read(File.absolute_path(File.dirname(__FILE__) + '/../../config/index.json'))
9
+ MultiJson.load(emoji_json, symbolize_keys: true)
10
+ end
11
+
12
+ @emoji_by_name = {}
13
+ @emoji_by_unicode = {}
14
+
15
+ mapping.each do |emoji_hash|
16
+ name = emoji_hash[:name]
17
+ @emoji_by_name[name] = emoji_hash if name
18
+
19
+ unicode = emoji_hash[:unicode]
20
+ @emoji_by_unicode[unicode] = emoji_hash if unicode
21
+ end
22
+
23
+ @emoji_name_regex = /:([a-z0-9\+\-_]+):/
24
+ @emoji_unicode_regex = /#{@emoji_by_unicode.keys.join('|')}/
25
+ end
26
+ # 主机地址
27
+ def asset_host
28
+ @asset_host || '//l.ruby-china.org'
29
+ end
30
+ # 设置主机地址
31
+ def asset_host=(host)
32
+ @asset_host = host
33
+ end
34
+ # 资源路径
35
+ def asset_path
36
+ @asset_path || '/assets/emojis/'
37
+ end
38
+ # 设置路径
39
+ def asset_path=(path)
40
+ @asset_path = path
41
+ end
42
+ # 通过(名称、字符)替换表情
43
+ def replace_emoji_with_images(string, size='64')
44
+ return string unless string
45
+
46
+ html ||= string.dup
47
+ html = replace_name_with_images(html, size)
48
+ html = replace_unicode_with_images(html.to_str, size)
49
+ puts html
50
+ puts '_'*88 + 'replace_unicode_with_images'
51
+ return html
52
+ end
53
+ # 通过(名称)替换表情
54
+ def replace_name_with_images(string, size='64')
55
+ unless string && string.match(names_regex)
56
+ return string
57
+ end
58
+
59
+ string.to_str.gsub(names_regex) do |match|
60
+ if names.include?($1)
61
+ %Q{<img class="emoji" src="#{ image_url_for_name($1) }" width="#{size}" height="#{size}" />}
62
+ else
63
+ match
64
+ end
65
+ end
66
+ end
67
+ # 通过(字符)替换表情
68
+ def replace_unicode_with_images(string, size='64')
69
+ unless string && string.match(unicodes_regex)
70
+ return string
71
+ end
72
+
73
+ html ||= string.dup
74
+ html.gsub!(unicodes_regex) do |unicode|
75
+ %Q{<img class="emoji" src="#{ image_url_for_unicode(unicode) }" width="#{size}" height="#{size}" />}
76
+ end
77
+ end
78
+ # 通过(名称)合成图片地址
79
+ def image_url_for_name(name)
80
+ "#{asset_host}#{ File.join(asset_path, name) }.png"
81
+ end
82
+ # 通过(字符)合成图片地址
83
+ def image_url_for_unicode(unicode)
84
+ emoji = find_by_unicode(unicode)
85
+ image_url_for_name(emoji[:name]) unless emoji.nil?
86
+ end
87
+ # 通过(字符)找表情
88
+ def find_by_unicode(moji)
89
+ @emoji_by_unicode[moji]
90
+ end
91
+ # 通过(名称)表情
92
+ def find_by_name(name)
93
+ @emoji_by_name[name]
94
+ end
95
+ # 名称列表
96
+ def names
97
+ @emoji_by_name.keys
98
+ end
99
+ # 字符列表
100
+ def unicodes
101
+ @emoji_by_unicode.keys
102
+ end
103
+ # 名称匹配表达式
104
+ def names_regex
105
+ @emoji_name_regex
106
+ end
107
+ # 字符匹配表达式
108
+ def unicodes_regex
109
+ @emoji_unicode_regex
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,3 @@
1
+ module SimpleFormat
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'simple_format/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "simple_format"
8
+ spec.version = SimpleFormat::VERSION
9
+ spec.authors = ["Howl王"]
10
+ spec.email = ["howl.wong@gmail.com"]
11
+ spec.summary = %q{Returns text transformed into HTML using simple formatting rules.}
12
+ spec.homepage = "https://github.com/mimosa/simple_format/"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency "multi_json"
21
+ spec.add_dependency "sanitize"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.5"
24
+ spec.add_development_dependency "rake"
25
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_format
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Howl王
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: multi_json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sanitize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - howl.wong@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - config/index.json
82
+ - lib/simple_format.rb
83
+ - lib/simple_format/auto_link.rb
84
+ - lib/simple_format/emoji.rb
85
+ - lib/simple_format/version.rb
86
+ - simple_format.gemspec
87
+ homepage: https://github.com/mimosa/simple_format/
88
+ licenses:
89
+ - MIT
90
+ metadata: {}
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 2.2.1
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: Returns text transformed into HTML using simple formatting rules.
111
+ test_files: []