ms_tools 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +9 -0
- data/lib/ms_tools/application_helpers.rb +108 -0
- data/lib/ms_tools/engine.rb +7 -0
- data/lib/ms_tools/head_helpers.rb +125 -0
- data/lib/ms_tools/sanitize.rb +155 -0
- data/lib/ms_tools.rb +9 -0
- data/test/helper.rb +10 -0
- data/test/test_ms_tools.rb +7 -0
- metadata +122 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 wmerrell
|
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.rdoc
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
= MsTools
|
2
|
+
|
3
|
+
== Overview
|
4
|
+
|
5
|
+
This is a collection of tools that I use in my projects. The tools included
|
6
|
+
are helpers for use in the head section of a page, an assortment of helpers for
|
7
|
+
use in pages and some enhanced tools to help with
|
8
|
+
sanitizing input for pages.
|
9
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module MsTools
|
2
|
+
module ApplicationHelpers
|
3
|
+
|
4
|
+
# Outputs the corresponding flash message if any are set
|
5
|
+
#
|
6
|
+
# This function is used to output the flash messages in a nice formated
|
7
|
+
# way. It is typically used in the application layout.
|
8
|
+
#
|
9
|
+
def flash_messages
|
10
|
+
messages = []
|
11
|
+
%w(notice warning).each do |msg|
|
12
|
+
messages << content_tag(:div, flash[msg.to_sym], :id => "flash-#{msg}") unless flash[msg.to_sym].blank?
|
13
|
+
end
|
14
|
+
if flash[:error].is_a?( Hash)
|
15
|
+
flash_to_display << activerecord_error_list(flash[:error])
|
16
|
+
else
|
17
|
+
flash_to_display = flash[:error]
|
18
|
+
end
|
19
|
+
messages << content_tag(:div, flash_to_display, :id => "flash-error") unless flash_to_display.blank?
|
20
|
+
raw(messages)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Normalizes image file names
|
24
|
+
#
|
25
|
+
# This function tries to find the file based on the name supplied. In
|
26
|
+
# normal use you will only need to supply the image file name without
|
27
|
+
# any extention. It will check for the supplied name as is, and with
|
28
|
+
# .png, .gif, or .jpg extentions added to the supplied name, in the
|
29
|
+
# public, public/images, and public/images/icons directories. If the
|
30
|
+
# file is found, it's normalized path name is returned. Note: It will
|
31
|
+
# also match any file that is explictly specified.
|
32
|
+
#
|
33
|
+
def clean_imagefile_name(name='')
|
34
|
+
root = Rails.public_path
|
35
|
+
filename = ""
|
36
|
+
# Shortcut to handle the most common cases.
|
37
|
+
if FileTest.exist?( File.join( root, "/images/#{name}.png" ) )
|
38
|
+
filename = "/images/#{name}.png"
|
39
|
+
elsif FileTest.exist?( File.join( root, "/images/icons/#{name}.png" ) )
|
40
|
+
filename = "/images/icons/#{name}.png"
|
41
|
+
else
|
42
|
+
# If not, check all
|
43
|
+
["", ".png", ".gif", ".jpg"].each do |ext|
|
44
|
+
# Check if full path has been specified
|
45
|
+
if FileTest.exist?( File.join( root, name + ext ) )
|
46
|
+
filename = name + ext
|
47
|
+
elsif FileTest.exist?( File.join( root, "/images/", name + ext ) )
|
48
|
+
filename = File.join( "/images/", name + ext )
|
49
|
+
elsif FileTest.exist?( File.join( root, "/images/icons/", name + ext ) )
|
50
|
+
filename = File.join( "/images/icons/", name + ext )
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
if filename.blank?
|
55
|
+
filename = "/images/broken.png"
|
56
|
+
end
|
57
|
+
filename
|
58
|
+
end
|
59
|
+
|
60
|
+
# Formats a "command_button" class link
|
61
|
+
#
|
62
|
+
# This function creates a link with an embedded image along with text. The
|
63
|
+
# link has a class of "command_button" added to it. It is expected that the
|
64
|
+
# "command_button" class will be formatted to resemble a button.
|
65
|
+
#
|
66
|
+
def command_button(text='', image='', url='', permission=nil, options = {})
|
67
|
+
options.stringify_keys!
|
68
|
+
text = text.blank? ? "" : text
|
69
|
+
img_tag = image_tag(clean_imagefile_name(image), :class=>"edit_icon", :alt=>" » ", :title=>text)
|
70
|
+
url = url.blank? ? "#" : url
|
71
|
+
options['class'] = options.has_key?('class') ? options['class'] + " command_button" : "command_button"
|
72
|
+
|
73
|
+
if permission.nil? || permission
|
74
|
+
link_to( img_tag + text, url, options )
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Formats a "menu_icon" class link
|
79
|
+
#
|
80
|
+
# This function creates a link with an embedded image along with text. The
|
81
|
+
# image has a class of "menu_icon" added to it. It is expected that the
|
82
|
+
# "menu_icon" class will be formatted to resemble a button.
|
83
|
+
#
|
84
|
+
def image_button(text='', image='', url='', permission=nil, options = {})
|
85
|
+
options.stringify_keys!
|
86
|
+
text = text.blank? ? "" : text
|
87
|
+
img_tag = image_tag(clean_imagefile_name(image), :class => 'menu_icon', :alt=>" » ", :title=>text)
|
88
|
+
url = url.blank? ? "#" : url
|
89
|
+
|
90
|
+
if permission.nil? || permission
|
91
|
+
link_to( img_tag + text, url, options )
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def activerecord_error_list(errors)
|
98
|
+
error_list = '<ul class="error_list">'
|
99
|
+
error_list << errors.collect do |e, m|
|
100
|
+
"<li>#{e.humanize unless e == "base"} #{m}</li>"
|
101
|
+
end.to_s << '</ul>'
|
102
|
+
error_list
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
ActionView::Base.send :include, MsTools::ApplicationHelpers
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module MsTools
|
2
|
+
module HeadHelpers
|
3
|
+
|
4
|
+
# Adds inline javascript data to the head section of a page.
|
5
|
+
#
|
6
|
+
# The intent of this function is to simplify your view code when you need
|
7
|
+
# javascript specifically for a particular page.
|
8
|
+
#
|
9
|
+
# Assumes that there is yield call in the <head> section of your layout
|
10
|
+
# like this:
|
11
|
+
# <script type="text/javascript">
|
12
|
+
# <%= yield :javascript_data %>
|
13
|
+
# </script>
|
14
|
+
#
|
15
|
+
#
|
16
|
+
# === Usage:
|
17
|
+
# <%- javascript do -%>
|
18
|
+
# alert("Hello world!");
|
19
|
+
# <%- end -%>
|
20
|
+
#
|
21
|
+
# This function expects a block which will be the javascript you
|
22
|
+
# wish to add to the page.
|
23
|
+
#
|
24
|
+
def javascript(*args, &block)
|
25
|
+
if block_given?
|
26
|
+
content = capture(&block)
|
27
|
+
content_for(:javascript_data) { content }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Adds javascript files to the head section of a page.
|
32
|
+
#
|
33
|
+
# The intent of this function is to simplify your view code when you need
|
34
|
+
# special javascript files for a particular page.
|
35
|
+
# This function may be called as many times as desired, the javascript files
|
36
|
+
# are added in the order they are called.
|
37
|
+
#
|
38
|
+
# Assumes that there is yield call in the <head> section of your layout
|
39
|
+
# like this:
|
40
|
+
# <%= yield :javascript_list %>
|
41
|
+
#
|
42
|
+
# All of the accumulated javascript files are added, in the order they were
|
43
|
+
# called when the page is generated.
|
44
|
+
#
|
45
|
+
# === Usage:
|
46
|
+
# <%- javascripts 'javascriptname' -%>
|
47
|
+
# or
|
48
|
+
# <%- javascripts ['javascriptname1', 'javascriptname2', ...] -%>
|
49
|
+
#
|
50
|
+
# The function takes either a string or and array of strings, and you
|
51
|
+
# may use an string that is valid for the +javascript_include_tag+ function.
|
52
|
+
# Be sure to include any paths for the file you wish to add.
|
53
|
+
#
|
54
|
+
def javascripts(*args)
|
55
|
+
items = args.class == Array ? args : args.to_a
|
56
|
+
items.each {|item|
|
57
|
+
content_for(:javascript_list) { javascript_include_tag item }
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
# Adds inline style information to the head section of a page.
|
62
|
+
#
|
63
|
+
# The intent of this function is to simplify your view code when you need
|
64
|
+
# special css style rules for a particular page.
|
65
|
+
#
|
66
|
+
# Assumes that there is yield call in the <head> section of your layout
|
67
|
+
# like this:
|
68
|
+
# <style type="text/css">
|
69
|
+
# <%= yield :stylesheet_data %>
|
70
|
+
# </style>
|
71
|
+
#
|
72
|
+
#
|
73
|
+
# === Usage:
|
74
|
+
# <%- stylesheet do -%>
|
75
|
+
# body {
|
76
|
+
# line-height: 1;
|
77
|
+
# color: black;
|
78
|
+
# background: white;
|
79
|
+
# }
|
80
|
+
# <%- end -%>
|
81
|
+
#
|
82
|
+
# This function expects a block which will be the css style rules you
|
83
|
+
# wish to add to the page. It can be any valid css text.
|
84
|
+
#
|
85
|
+
def stylesheet(*args, &block)
|
86
|
+
if block_given?
|
87
|
+
content = capture(&block)
|
88
|
+
content_for(:stylesheet_data) { content }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Adds style sheet files to the head section of a page.
|
93
|
+
#
|
94
|
+
# The intent of this function is to simplify your view code when you need
|
95
|
+
# special style sheets for a particular page.
|
96
|
+
# This function may be called as many times as desired, the style sheets
|
97
|
+
# are added in the order they are called.
|
98
|
+
#
|
99
|
+
# Assumes that there is yield call in the <head> section of your layout
|
100
|
+
# like this:
|
101
|
+
# <%= yield :stylesheet_list %>
|
102
|
+
#
|
103
|
+
# All of the accumulated style sheets are added, in the order they were
|
104
|
+
# called when the page is generated.
|
105
|
+
#
|
106
|
+
# === Usage:
|
107
|
+
# <%- stylesheets 'stylesheetname' -%>
|
108
|
+
# or
|
109
|
+
# <%- stylesheets ['stylesheetname1', 'stylesheetname2', ...] -%>
|
110
|
+
#
|
111
|
+
# The function takes either a string or and array of strings, and you
|
112
|
+
# may use an string that is valid for the +stylesheet_link_tag+ function.
|
113
|
+
# Be sure to include any paths for the file you wish to add.
|
114
|
+
#
|
115
|
+
def stylesheets(*args)
|
116
|
+
items = args.class == Array ? args : args.to_a
|
117
|
+
items.each {|item|
|
118
|
+
content_for(:stylesheet_list) { stylesheet_link_tag item }
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
ActionView::Base.send :include, MsTools::HeadHelpers
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module MsTools
|
2
|
+
module MsSanitize
|
3
|
+
|
4
|
+
module Config
|
5
|
+
DEFAULT = Sanitize::Config::DEFAULT.update({:remove_contents => ['script', 'embed', 'iframe']})
|
6
|
+
BASIC = Sanitize::Config::BASIC.update({:remove_contents => ['script', 'embed', 'iframe']})
|
7
|
+
RESTRICTED = Sanitize::Config::RESTRICTED.update({:remove_contents => ['script', 'embed', 'iframe']})
|
8
|
+
RELAXED = Sanitize::Config::RELAXED.update({:remove_contents => ['script', 'embed', 'iframe']})
|
9
|
+
EXTENDED = {
|
10
|
+
:elements => [
|
11
|
+
'a', 'b', 'blockquote', 'br', 'caption', 'cite', 'code', 'col',
|
12
|
+
'colgroup', 'dd', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
|
13
|
+
'hr', 'i', 'img', 'li', 'ol', 'p', 'pre', 'q', 'small', 'strike',
|
14
|
+
'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead',
|
15
|
+
'tr', 'u', 'ul'],
|
16
|
+
|
17
|
+
:attributes => {
|
18
|
+
'a' => ['class', 'href', 'title'],
|
19
|
+
'blockquote' => ['class', 'cite'],
|
20
|
+
'br' => ['class'],
|
21
|
+
'code' => ['class'],
|
22
|
+
'col' => ['class', 'span', 'width'],
|
23
|
+
'colgroup' => ['class', 'span', 'width'],
|
24
|
+
'hr' => ['class'],
|
25
|
+
'img' => ['class', 'align', 'alt', 'height', 'src', 'title', 'width', 'title'],
|
26
|
+
'li' => ['class', 'title'],
|
27
|
+
'ol' => ['class', 'start', 'type'],
|
28
|
+
'p' => ['class', 'title'],
|
29
|
+
'q' => ['class', 'cite'],
|
30
|
+
'table' => ['border', 'class', 'cellspacing', 'cellpadding', 'summary', 'width'],
|
31
|
+
'td' => ['abbr', 'axis', 'class', 'colspan', 'rowspan', 'width', 'title'],
|
32
|
+
'th' => ['abbr', 'axis', 'class', 'colspan', 'rowspan', 'scope', 'width', 'title'],
|
33
|
+
'ul' => ['class', 'type']
|
34
|
+
},
|
35
|
+
|
36
|
+
:protocols => {
|
37
|
+
'a' => {'href' => ['ftp', 'http', 'https', 'mailto', :relative]},
|
38
|
+
'blockquote' => {'cite' => ['http', 'https', :relative]},
|
39
|
+
'img' => {'src' => ['http', 'https', :relative]},
|
40
|
+
'q' => {'cite' => ['http', 'https', :relative]}
|
41
|
+
},
|
42
|
+
|
43
|
+
:remove_contents => ['script', 'embed', 'iframe']
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns a sanitized copy of _html_, using the settings in _config_ if
|
48
|
+
# specified.
|
49
|
+
def msclean(html, options = {})
|
50
|
+
config = options.delete(:config) || {}
|
51
|
+
radius = options.delete(:radius) || false
|
52
|
+
if( radius ) then
|
53
|
+
Sanitize.clean(html.gsub(/<r:([a-z0-9 _'"=-]+) \/>/i, '(r:\1 /)'), config).gsub(' ',"").gsub(/\(r:([a-z0-9 _'"=-]+) \/\)/i, '<r:\1 />')
|
54
|
+
else
|
55
|
+
Sanitize.clean(html, config).gsub(' ',"")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Performs Sanitize#clean in place, returning _html_, or +nil+ if no changes
|
60
|
+
# were made.
|
61
|
+
def msclean!(html, options = {})
|
62
|
+
config = options.delete(:config) || {}
|
63
|
+
radius = options.delete(:radius) || false
|
64
|
+
if( radius ) then
|
65
|
+
Sanitize.clean!(html.gsub(/<r:([a-z0-9 _'"=-]+) \/>/i, '(r:\1 /)'), config).gsub(' ',"").gsub(/\(r:([a-z0-9 _'"=-]+) \/\)/i, '<r:\1 />')
|
66
|
+
else
|
67
|
+
Sanitize.clean!(html, config).gsub(' ',"")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# A sanitizer before filter that walks all parameters before any
|
72
|
+
# processing takes place.
|
73
|
+
#
|
74
|
+
# == Description
|
75
|
+
#
|
76
|
+
# This is based on the sanitize_params plugin written by Jay Laney, updated
|
77
|
+
# by Danny Sofer to work with the Sanitizer module that is now part of
|
78
|
+
# the Rails core.
|
79
|
+
#
|
80
|
+
# The original version of sanitize_params used Rick Olsen's white_list plugin,
|
81
|
+
# but as Rick pointed out some time ago, "I recently just refactored a lot of
|
82
|
+
# that code into the html tokenizer library. You can now access the classes
|
83
|
+
# directly as HTML::Sanitizer, HTML::LinkSanitizer, and HTML::WhiteListSanitizer."
|
84
|
+
#
|
85
|
+
# Danny Sofer's version of sanitize_params does exactly that. Otherwise,
|
86
|
+
# it is unchanged from Jay's original code designed for scrubbing your
|
87
|
+
# user input clean.
|
88
|
+
#
|
89
|
+
# I modified this to work with Ryan Grove's Sanitize gem which is required
|
90
|
+
# by this function.
|
91
|
+
#
|
92
|
+
# == Usage
|
93
|
+
#
|
94
|
+
# in application.rb:
|
95
|
+
#
|
96
|
+
# before_filter :sanitize_params
|
97
|
+
#
|
98
|
+
# Alternatively, add the filter to your controllers selectively.
|
99
|
+
#
|
100
|
+
# == Contact
|
101
|
+
#
|
102
|
+
# The original sanitize_params plugin was written by Jay Laney and is still
|
103
|
+
# available at http://code.google.com/p/sanitizeparams/
|
104
|
+
#
|
105
|
+
# This version was dereived from the forked version tweaked by Danny Sofer,
|
106
|
+
# which can be found at http://github.com/sofer/sanitize_params.
|
107
|
+
#
|
108
|
+
def sanitize_params(params = params)
|
109
|
+
params = walk_hash(params) if params
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns a sanitized copy of _html_, using the settings in _config_ if
|
113
|
+
# specified.
|
114
|
+
def sanitize(html, options = {})
|
115
|
+
msclean(html, options)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Performs Sanitize#clean in place, returning _html_, or +nil+ if no changes
|
119
|
+
# were made.
|
120
|
+
def sanitize!(html, options = {})
|
121
|
+
msclean!(html, options)
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def walk_hash(hash)
|
127
|
+
hash.keys.each do |key|
|
128
|
+
if hash[key].is_a? String
|
129
|
+
hash[key] = sanitize(hash[key])
|
130
|
+
elsif hash[key].is_a? Hash
|
131
|
+
hash[key] = walk_hash(hash[key])
|
132
|
+
elsif hash[key].is_a? Array
|
133
|
+
hash[key] = walk_array(hash[key])
|
134
|
+
end
|
135
|
+
end
|
136
|
+
hash
|
137
|
+
end
|
138
|
+
|
139
|
+
def walk_array(array)
|
140
|
+
array.each_with_index do |el,i|
|
141
|
+
if el.is_a? String
|
142
|
+
array[i] = sanitize(el)
|
143
|
+
elsif el.is_a? Hash
|
144
|
+
array[i] = walk_hash(el)
|
145
|
+
elsif el.is_a? Array
|
146
|
+
array[i] = walk_array(el)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
array
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
ActionController::Base.send :include, MsTools::MsSanitize
|
data/lib/ms_tools.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'action_view'
|
2
|
+
require 'sanitize'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'ms_tools/engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3
|
5
|
+
require 'ms_tools/application_helpers'
|
6
|
+
require 'ms_tools/head_helpers'
|
7
|
+
require 'ms_tools/sanitize'
|
8
|
+
module MsTools
|
9
|
+
end
|
data/test/helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ms_tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 0.4.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Will Merrell
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-11-13 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: nokogiri
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 1
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 4
|
33
|
+
- 3
|
34
|
+
version: 1.4.3
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: sanitize
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 29
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 2
|
49
|
+
- 1
|
50
|
+
version: 1.2.1
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: thoughtbot-shoulda
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
type: :development
|
66
|
+
version_requirements: *id003
|
67
|
+
description: A collection of functions and tools I use in my projects. Longer description.
|
68
|
+
email: will@morelandsolutions.com
|
69
|
+
executables: []
|
70
|
+
|
71
|
+
extensions: []
|
72
|
+
|
73
|
+
extra_rdoc_files:
|
74
|
+
- LICENSE
|
75
|
+
- README.rdoc
|
76
|
+
files:
|
77
|
+
- lib/ms_tools.rb
|
78
|
+
- lib/ms_tools/application_helpers.rb
|
79
|
+
- lib/ms_tools/engine.rb
|
80
|
+
- lib/ms_tools/head_helpers.rb
|
81
|
+
- lib/ms_tools/sanitize.rb
|
82
|
+
- LICENSE
|
83
|
+
- README.rdoc
|
84
|
+
- test/test_ms_tools.rb
|
85
|
+
- test/helper.rb
|
86
|
+
has_rdoc: true
|
87
|
+
homepage: http://github.com/wmerrell/ms_tools
|
88
|
+
licenses: []
|
89
|
+
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options:
|
92
|
+
- --charset=UTF-8
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
hash: 3
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
version: "0"
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
hash: 3
|
110
|
+
segments:
|
111
|
+
- 0
|
112
|
+
version: "0"
|
113
|
+
requirements: []
|
114
|
+
|
115
|
+
rubyforge_project:
|
116
|
+
rubygems_version: 1.3.7
|
117
|
+
signing_key:
|
118
|
+
specification_version: 3
|
119
|
+
summary: A collection of functions and tools I use in my projects.
|
120
|
+
test_files:
|
121
|
+
- test/test_ms_tools.rb
|
122
|
+
- test/helper.rb
|