ms_tools 0.4.0
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/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
|