simple_format 0.0.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.
@@ -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: []