mir_utility 0.3.29

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ Manifest
2
+ README.rdoc
3
+ Rakefile
4
+ init.rb
5
+ lib/mir_form_builder.rb
6
+ lib/mir_utility.rb
@@ -0,0 +1,32 @@
1
+ = Mir Utility
2
+
3
+ Standard extensions for Mir Rails apps.
4
+
5
+ == Prerequisites
6
+
7
+ sudo gem install echoe
8
+
9
+ == Install
10
+
11
+ Clone the git repo:
12
+
13
+ git clone git@github.com:Bantik/MirUtility.git
14
+
15
+ To build from your local source:
16
+
17
+ rake manifest
18
+ rake build_gemspec
19
+ gem build mir_utility.gemspec
20
+ sudo gem install mir_utility
21
+
22
+ == Usage
23
+
24
+ See the RDocs.
25
+
26
+ == Revising the Gem
27
+
28
+ * Make your changes.
29
+ * Test locally with rspec.
30
+ * Revise the version number in Rakefile.
31
+ * Follow build-from-local-source instructions above.
32
+ * Commit and push your changes.
@@ -0,0 +1,19 @@
1
+ require(File.join(File.dirname(__FILE__), 'config', 'boot'))
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+ require 'rake/testtask'
6
+ require 'rake/rdoctask'
7
+ require 'tasks/rails'
8
+ require 'echoe'
9
+
10
+ Echoe.new('mir_utility', '0.3.29') do |p|
11
+ p.description = "Standard extensions for Mir Rails apps."
12
+ p.url = "http://github.com/bantik/mir_utility"
13
+ p.author = "Corey Ehmke and Rod Monje"
14
+ p.email = "corey@seologic.com"
15
+ p.ignore_pattern = ["app/**/*", "config/**/*", "db/**/*", "lib/tasks/*", "log/", "public/**/*", "script/**/*", "spec/**/*", "tmp/"]
16
+ p.development_dependencies = []
17
+ end
18
+
19
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'mir_utility'
@@ -0,0 +1,176 @@
1
+ # == Configuration
2
+ #
3
+ # === Configure your application to default to the custom form builder
4
+ #
5
+ # In app/controllers/application_controller.rb:
6
+ #
7
+ # class ApplicationController < ActionController::Base
8
+ # ActionView::Base.default_form_builder = MirFormBuilder
9
+ #
10
+ # == Usage
11
+ #
12
+ # === Default form field with label:
13
+ #
14
+ # <%= f.text_field :last_name -%>
15
+ #
16
+ # Returns:
17
+ #
18
+ # <fieldset>
19
+ # <label for="user_last_name">Last Name</label><br />
20
+ # <input id="user_last_name" name="user[last_name]" size="30" type="text" />
21
+ # </fieldset>
22
+ #
23
+ # === Form field with custom label:
24
+ #
25
+ # <%= f.text_field :first_name, :label => 'Custom' -%>
26
+ #
27
+ # Returns:
28
+ #
29
+ # <fieldset>
30
+ # <label for="user_first_name">Custom</label><br />
31
+ # <input id="user_first_name" name="user[first_name]" size="30" type="text" />
32
+ # </fieldset>
33
+ #
34
+ # === Form field with no label
35
+ #
36
+ # <%= f.text_field :search, :label => false -%>
37
+ #
38
+ # Returns:
39
+ #
40
+ # <input id="search" name="search" size="30" type="text" />
41
+ #
42
+ # === Form field with inline help (? icon which reveals help content when clicked):
43
+ #
44
+ # <%= f.password_field :password %>
45
+ #
46
+ # Returns:
47
+ #
48
+ # <fieldset>
49
+ # <label for="password">Password: <img src="/images/icons/help_icon.png"
50
+ # onclick="$('password_help').toggle();" class='inline_icon' /></label><br />
51
+ # <div class="inline_help" id="password_help" style="display: none;">
52
+ # <p>Here are some detailed instructions on valid passwords.</p>
53
+ # </div>
54
+ # <input id="user_password" name="user[password]" size="30" type="password" />
55
+ # </fieldset>
56
+ #
57
+ # === Form field with instructions (show immediately below the label):
58
+ #
59
+ # <%= f.password_field :password_confirmation %>
60
+ #
61
+ # Returns:
62
+ #
63
+ # <fieldset>
64
+ # <label for="password_confirmation">
65
+ # Confirm Password:
66
+ # <span class="instructions">Enter your password again to confirm.</span>
67
+ # </label><br />
68
+ # <input id="user_password_confirmation" name="user[password_confirmation]" size="30" type="password" />
69
+ # </fieldset>
70
+ #
71
+ # === Check box with label in addition to checkbox value text
72
+ # (E.g. 'Foo' appears above the checkbox, and 'Something' next to it):
73
+ #
74
+ # <%= f.check_box :foo, :inline_label => 'Something' -%>
75
+ #
76
+ # Returns:
77
+ #
78
+ # <fieldset>
79
+ # <label for="user_foo">Foo</label><br />
80
+ # <input name="user[foo]" type="hidden" value="0" />
81
+ # <input id="user_foo" name="user[foo]" type="checkbox" value="1" />
82
+ # <label class="inline" for="user_foo">Something</label><br style='clear: both;'/><br />
83
+ # </fieldset>
84
+ #
85
+ # === Don't wrap fields in a fieldset
86
+ #
87
+ # <%= f.text_field :query, :label => 'Search terms:', :fieldset => false -%>
88
+ #
89
+ # Returns
90
+ #
91
+ # <label for="search_terms_query"><br />
92
+ # <input id="search_terms_query" name="search_terms_query" size="30" />
93
+ #
94
+ # == Troubleshooting
95
+ #
96
+ # If you're seeing double form labels, it's because you still have <%= label -%> elements in your forms.
97
+ #
98
+ class MirFormBuilder < ActionView::Helpers::FormBuilder
99
+ include ApplicationHelper
100
+
101
+ helpers = field_helpers +
102
+ %w{date_select datetime_select time_select} +
103
+ %w{collection_select select country_select time_zone_select} -
104
+ %w{hidden_field label fields_for}
105
+
106
+ helpers.each do |name|
107
+ define_method(name) do |field, *args|
108
+ RAILS_DEFAULT_LOGGER.debug "Processing #{name}"
109
+ RAILS_DEFAULT_LOGGER.debug " Arguments: #{args.inspect}"
110
+
111
+ # capture first array as select choices
112
+ choices = args.detect{ |a| a.is_a?(Array) } || []
113
+ args.delete(choices)
114
+
115
+ # capture first hash as options
116
+ options = args.detect{ |a| a.is_a?(Hash) } || {}
117
+ args.delete(options)
118
+
119
+ # capture second hash as HTML options
120
+ html_options = args.detect{ |a| a.is_a?(Hash) } || {}
121
+ args.delete(html_options)
122
+
123
+ include_label = true
124
+
125
+ RAILS_DEFAULT_LOGGER.debug " Choices: #{choices.inspect}"
126
+ RAILS_DEFAULT_LOGGER.debug " Options: #{options.inspect}"
127
+ RAILS_DEFAULT_LOGGER.debug " HTML options: #{html_options.inspect}"
128
+ RAILS_DEFAULT_LOGGER.debug " Remaining arguments: #{args.inspect}"
129
+
130
+ if options[:label].nil? # Not specified. Default to humanized version of field id.
131
+ _label_text = field.to_s.humanize.capitalize_words
132
+ elsif options[:label]
133
+ _label_text = options.delete :label
134
+ # options[:label] is false!
135
+ else
136
+ include_label = options.delete(:label)
137
+ end
138
+
139
+ # Create label, if label text was provided or created.
140
+ if _label_text || options[:instructions]
141
+ if options[:instructions]
142
+ _label = tag_for_label_with_instructions(_label_text, field, options.delete(:instructions))
143
+ elsif options[:help]
144
+ _label = tag_for_label_with_inline_help(_label_text, field, options.delete(:help))
145
+ elsif include_label
146
+ _label = label(field, _label_text) + @template.tag('br')
147
+ end
148
+ end
149
+
150
+ if options[:inline_label] # Handle inline labels, e.g. for checkboxes
151
+ _inline_label = label(field, options.delete(:inline_label), :class => 'inline') + @template.tag('br', :style => 'clear: both;')
152
+ end
153
+
154
+ _field = nil
155
+
156
+ if name == 'select'
157
+ _field = super(field, choices, options, html_options)
158
+ elsif name.include? 'select'
159
+ _field = super(field, options, html_options)
160
+ else
161
+ if name == 'radio_button'
162
+ # invert arguments
163
+ _field = super(field, args, options)
164
+ else
165
+ _field = args.compact.blank? ? super(field, options) : super(field, options, args)
166
+ end
167
+ end
168
+
169
+ if options[:fieldset] == false
170
+ "#{_label}#{_field}#{_inline_label}"
171
+ else
172
+ @template.content_tag(:fieldset, "#{_label}#{_field}#{_inline_label}")
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,853 @@
1
+ require 'singleton'
2
+ require 'soap/header/simplehandler'
3
+
4
+ module MirUtility
5
+ MONTHS = {
6
+ 0 => "JAN",
7
+ 1 => "FEB",
8
+ 2 => "MAR",
9
+ 3 => "APR",
10
+ 4 => "MAY",
11
+ 5 => "JUN",
12
+ 6 => "JUL",
13
+ 7 => "AUG",
14
+ 8 => "SEP",
15
+ 9 => "OCT",
16
+ 10 => "NOV",
17
+ 11 => "DEC"
18
+ }
19
+
20
+ STATE_CODES = { 'Alabama' => 'AL', 'Alaska' => 'AK', 'Arizona' => 'AZ', 'Arkansas' => 'AR', 'California' => 'CA', 'Colorado' => 'CO', 'Connecticut' => 'CT', 'Delaware' => 'DE', 'Florida' => 'FL', 'Georgia' => 'GA', 'Hawaii' => 'HI', 'Idaho' => 'ID', 'Illinois' => 'IL', 'Indiana' => 'IN', 'Iowa' => 'IA', 'Kansas' => 'KS', 'Kentucky' => 'KY', 'Louisiana' => 'LA', 'Maine' => 'ME', 'Maryland' => 'MD', 'Massachusetts' => 'MA', 'Michigan' => 'MI', 'Minnesota' => 'MN', 'Mississippi' => 'MS', 'Missouri' => 'MO', 'Montana' => 'MT', 'Nebraska' => 'NE', 'Nevada' => 'NV', 'New Hampshire' => 'NH', 'New Jersey' => 'NJ', 'New Mexico' => 'NM', 'New York' => 'NY', 'North Carolina' => 'NC', 'North Dakota' => 'ND', 'Ohio' => 'OH', 'Oklahoma' => 'OK', 'Oregon' => 'OR', 'Pennsylvania' => 'PA', 'Puerto Rico' => 'PR', 'Rhode Island' => 'RI', 'South Carolina' => 'SC', 'South Dakota' => 'SD', 'Tennessee' => 'TN', 'Texas' => 'TX', 'Utah' => 'UT', 'Vermont' => 'VT', 'Virginia' => 'VA', 'Washington' => 'WA', 'Washington DC' => 'DC', 'West Virginia' => 'WV', 'Wisconsin' => 'WI', 'Wyoming' => 'WY', 'Alberta' => 'AB', 'British Columbia' => 'BC', 'Manitoba' => 'MB', 'New Brunswick' => 'NB', 'Newfoundland and Labrador' => 'NL', 'Northwest Territories' => 'NT', 'Nova Scotia' => 'NS', 'Nunavut' => 'NU', 'Ontario' => 'ON', 'Prince Edward Island' => 'PE', 'Quebec' => 'QC', 'Saskatchewan' => 'SK', 'Yukon' => 'YT' }
21
+
22
+ def self.canonical_url(url)
23
+ (url + '/').gsub(/\/\/$/,'/')
24
+ end
25
+
26
+ def self.destroy_old_sessions( timestamp )
27
+ ActiveRecord::SessionStore::Session.destroy_all(
28
+ ['updated_at < ?', timestamp]
29
+ )
30
+ end
31
+
32
+ # Copied from FriendlyId 2.2.7 for backward compatibility. Use gem's default behavior instead: http://github.com/norman/friendly_id.
33
+ def self.normalize(slug_text)
34
+ return "" if slug_text.nil? || slug_text == ""
35
+ ActiveSupport::Multibyte.proxy_class.new(slug_text.to_s).normalize(:kc).
36
+ gsub(/[\W]/u, ' ').
37
+ strip.
38
+ gsub(/\s+/u, '-').
39
+ gsub(/-\z/u, '').
40
+ downcase.
41
+ to_s
42
+ end
43
+
44
+ def self.normalize_slug(text)
45
+ warn "[DEPRECATION] `MirUtility.normalize_slug` is deprecated. Use FriendlyId's default behavior instead: http://github.com/norman/friendly_id."
46
+ _normalized = MirUtility.normalize(text)
47
+ _normalized.gsub!('-', '_') # change - to _
48
+ _normalized.gsub!(/[_]+/, '_') # truncate multiple _
49
+ _normalized
50
+ end
51
+
52
+ def self.state_name_for(abbreviation)
53
+ STATE_CODES.value?(abbreviation.to_s.upcase) && STATE_CODES.find{|k,v| v == abbreviation.to_s.upcase}[0]
54
+ end
55
+
56
+ module CoreExtensions
57
+ module String
58
+ # Add whatever helpers you want, then wrap any methods that you want from the
59
+ # ActionView::Helpers::Foo class
60
+ module NumberHelper
61
+ def number_to_phone(s, options = {})
62
+ StringHelperSingleton.instance.number_to_phone(s, options)
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ class ActionController::Base
71
+ include MirUtility
72
+ require 'socket'
73
+
74
+ def self.local_ip
75
+ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily
76
+
77
+ UDPSocket.open do |s|
78
+ s.connect '64.233.187.99', 1
79
+ s.addr.last
80
+ end
81
+ ensure
82
+ Socket.do_not_reverse_lookup = orig
83
+ end
84
+
85
+ # Returns a sanitized column parameter suitable for SQL order-by clauses.
86
+ def sanitize_by_param(allowed=[], default='id')
87
+ sanitize_params params && params[:by], allowed, default
88
+ end
89
+
90
+ # Returns a sanitized direction parameter suitable for SQL order-by clauses.
91
+ def sanitize_dir_param(default='ASC')
92
+ sanitize_params params && params[:dir], ['ASC', 'DESC'], default
93
+ end
94
+
95
+ # Use this method to prevent SQL injection vulnerabilities by verifying that a user-provided
96
+ # parameter is on a whitelist of allowed values.
97
+ #
98
+ # Accepts a value, a list of allowed values, and a default value.
99
+ # Returns the value if allowed, otherwise the default.
100
+ def sanitize_params(supplied='', allowed=[], default=nil)
101
+ raise ArgumentError, "A default value is required." unless default
102
+ return default.to_s if supplied.blank? || allowed.blank? || ! allowed.map{ |x| x.to_s }.include?(supplied.to_s)
103
+ return supplied
104
+ end
105
+ end
106
+
107
+ module ActiveRecord::Validations::ClassMethods
108
+
109
+ # Overrides validates associates.
110
+ # We do this to allow more better error messages to bubble up from associated models.
111
+ # Adapted from thread at http://pivotallabs.com/users/nick/blog/articles/359-alias-method-chain-validates-associated-informative-error-message
112
+ def validates_associated(*associations)
113
+ # These configuration lines are required if your going to use any conditionals with the validates associated - Rails 2.2.2 safe!
114
+ configuration = { :message => I18n.translate('activerecord.errors.messages'), :on => :save }
115
+ configuration.update(associations.extract_options!)
116
+ associations.each do |association|
117
+ class_eval do
118
+ validates_each(associations,configuration) do |record, associate_name, value|
119
+ associates = record.send(associate_name)
120
+ associates = [associates] unless associates.respond_to?('each')
121
+ associates.each{ |associate| associate.errors.each{ |key, value2| record.errors.add("", "#{value2}") } if associate && !associate.valid? }
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ class ActiveRecord::Base
129
+ include MirUtility
130
+
131
+ #FIXME Extending AR in this way will stop working under Rails 2.3.2 for some reason.
132
+
133
+ named_scope :order_by, lambda{ |col, dir| {:order => (col.blank?) ? ( (dir.blank?) ? 'id' : dir ) : "#{col} #{dir}"} }
134
+ named_scope :limit, lambda { |num| { :limit => num } }
135
+
136
+ # TODO: call the column_names class method on the subclass
137
+ # named_scope :sort_by, lambda{ |col, dir| {:order => (col.blank?) ? ( (dir.blank?) ? (Client.column_names.include?('name') ? 'name' : 'id') : h(dir) ) : "#{h(col)} #{h(dir)}"} }
138
+
139
+ # Returns an array of SQL conditions suitable for use with ActiveRecord's finder.
140
+ # valid_criteria is an array of valid search fields.
141
+ # pairs is a hash of field names and values.
142
+ def self.search_conditions( valid_search_criteria, pairs, operator = 'OR' )
143
+ if valid_search_criteria.detect{ |_c| ! pairs[_c].blank? } || ! pairs[:query].blank?
144
+ _conditions = []
145
+ _or_clause = ''
146
+ _or_clause_values = []
147
+ _int_terms = {}
148
+ _text_terms = {}
149
+
150
+ # build or clause for keyword search
151
+ unless pairs[:query].blank? || ! self.respond_to?(:flattened_content)
152
+ pairs[:query].split(' ').each do |keyword|
153
+ _or_clause += 'flattened_content LIKE ? OR '
154
+ _or_clause_values << "%#{keyword}%"
155
+ end
156
+
157
+ _or_clause.gsub!( / OR $/, '')
158
+ end
159
+
160
+ # iterate across each valid search field
161
+ valid_search_criteria.each do |_field|
162
+ # build or clause for keyword search
163
+ unless pairs[:query].blank? || self.respond_to?(:flattened_content)
164
+ pairs[:query].split(' ').each do |keyword|
165
+ _or_clause += "#{_field} LIKE ? OR "
166
+ _or_clause_values << "%#{keyword}%"
167
+ end
168
+ end
169
+
170
+ # build hashes of integer and/or text search fields and values for each non-blank param
171
+ if ! pairs[_field].blank?
172
+ _field.to_s =~ /^id$|_id$|\?$/ ? _int_terms[_field.to_s.gsub('?', '')] = pairs[_field] : _text_terms[_field] = pairs[_field]
173
+ end
174
+ end
175
+
176
+ _or_clause.gsub!( / OR $/, '')
177
+
178
+ # convert the hash to parametric SQL
179
+ if _or_clause.blank?
180
+ _conditions = sql_conditions_for( _int_terms, _text_terms, nil, operator )
181
+ elsif _int_terms.keys.empty? && _text_terms.keys.empty?
182
+ _conditions = [ _or_clause ]
183
+ else
184
+ _conditions = sql_conditions_for( _int_terms, _text_terms, _or_clause, operator )
185
+ end
186
+
187
+ # add integer values
188
+ _int_terms.keys.each{ |key| _conditions << _int_terms[key] }
189
+ # add wildcard-padded values
190
+ _text_terms.keys.each{ |key| _conditions << "%#{_text_terms[key]}%" }
191
+
192
+ unless _or_clause_values.empty?
193
+ # add keywords
194
+ _conditions += _or_clause_values
195
+ end
196
+
197
+ return _conditions
198
+ else
199
+ return nil
200
+ end
201
+ end
202
+
203
+ def self.to_option_values
204
+ self.all.sort_by{ |x| x.name }.map{ |x| [x.name, x.id] }
205
+ end
206
+
207
+ # Strips the specified attribute's value.
208
+ def strip(attribute)
209
+ value = self[attribute]
210
+ self.send("#{attribute}=", value && value.strip)
211
+ end
212
+
213
+ private
214
+
215
+ def self.sql_conditions_for( integer_fields, text_fields, or_clause = nil, operator = 'OR' )
216
+ if integer_fields.empty? && ! text_fields.empty?
217
+ [ text_fields.keys.map{ |k| k } * " LIKE ? #{operator} " + ' LIKE ?' + (or_clause ? " #{operator} #{or_clause}" : '') ]
218
+ elsif ! integer_fields.empty? && text_fields.empty?
219
+ [ integer_fields.keys.map{ |k| k } * " = ? #{operator} " + ' = ?' + (or_clause ? " #{operator} #{or_clause}" : '') ]
220
+ else
221
+ [ integer_fields.keys.map{ |k| k } * " = ? #{operator} " + " = ? #{operator} " + text_fields.keys.map{ |k| k } * " LIKE ? #{operator} " + ' LIKE ?' + (or_clause ? " #{operator} #{or_clause}" : '') ]
222
+ end
223
+ end
224
+ end
225
+
226
+ module ApplicationHelper
227
+
228
+ SELECT_PROMPT = 'Select...'
229
+ SELECT_PROMPT_OPTION = "<option value=''>#{SELECT_PROMPT}</option>"
230
+
231
+ def action?( expression )
232
+ !! ( expression.class == Regexp ? controller.action_name =~ expression : controller.action_name == expression )
233
+ end
234
+
235
+ # Formats an array with HTML line breaks, or the specified delimiter.
236
+ def array_to_lines(array, delimiter = '<br />')
237
+ return unless array.is_a?(Array)
238
+ array.blank? ? nil : array * delimiter
239
+ end
240
+
241
+ def checkmark
242
+ %{<div class="checkmark"></div>}
243
+ end
244
+
245
+ def controller?( expression )
246
+ !! ( expression.class == Regexp ? controller.controller_name =~ expression : controller.controller_name == expression )
247
+ end
248
+
249
+ # Display CRUD icons or links, according to setting in use_crud_icons method.
250
+ #
251
+ # In application_helper.rb:
252
+ #
253
+ # def use_crud_icons
254
+ # true
255
+ # end
256
+ #
257
+ # Then use in index views like this:
258
+ #
259
+ # <td class="crud_links"><%= crud_links(my_model, 'my_model', [:show, :edit, :delete]) -%></td>
260
+ #
261
+ def crud_links(model, instance_name, actions, args={})
262
+ _html = ''
263
+ _path = args.delete(:path) || model
264
+ _edit_path = args.delete(:edit_path) || eval("edit_#{instance_name}_path(model)") if actions.include?(:edit)
265
+ _options = args.empty? ? '' : ", #{args.map{|k,v| ":#{k} => #{v}"}}"
266
+
267
+ if use_crud_icons
268
+ _html << link_to(image_tag('icons/view.png', :class => 'crud_icon', :width => 14, :height => 14), _path, :title => "View#{_options}") if actions.include?(:show)
269
+ _html << link_to(image_tag('icons/edit.png', :class => 'crud_icon', :width => 14, :height => 14), _edit_path, :title => "Edit#{_options}") if actions.include?(:edit)
270
+ _html << link_to(image_tag('icons/delete.png', :class => 'crud_icon', :width => 14, :height => 14), _path, :confirm => 'Are you sure? This action cannot be undone.', :method => :delete, :title => "Delete#{_options}") if actions.include?(:delete)
271
+ else
272
+ _html << link_to('View', _path, :title => 'View', :class => "crud_link#{_options}") if actions.include?(:show)
273
+ _html << link_to('Edit', _edit_path, :title => 'Edit', :class => "crud_link#{_options}") if actions.include?(:edit)
274
+ _html << link_to('Delete', _path, :confirm => 'Are you sure? This action cannot be undone.', :method => :delete, :title => 'Delete', :class => "crud_link#{_options}") if actions.include?(:delete)
275
+ end
276
+
277
+ _html
278
+ end
279
+
280
+ # Display CRUD icons or links, according to setting in use_crud_icons method.
281
+ # This method works with nested resources.
282
+ # Use in index views like this:
283
+ #
284
+ # <td class="crud_links"><%= crud_links_for_nested_resource(@my_model, my_nested_model, 'my_model', 'my_nested_model', [:show, :edit, :delete]) -%></td>
285
+ #
286
+ def crud_links_for_nested_resource(model, nested_model, model_instance_name, nested_model_instance_name, actions, args={})
287
+ crud_links model, model_instance_name, actions, args.merge(:edit_path => eval("edit_#{model_instance_name}_#{nested_model_instance_name}_path(model, nested_model)"), :path => [model, nested_model])
288
+ end
289
+
290
+ # DRY way to return a legend tag that renders correctly in all browsers. This variation allows
291
+ # for more "stuff" inside the legend tag, e.g. expand/collapse controls, without having to worry
292
+ # about escape sequences.
293
+ #
294
+ # Sample usage:
295
+ #
296
+ # <%- legend_block do -%>
297
+ # <span id="hide_or_show_backlinks" class="show_link" style="background-color: #999999;
298
+ # border: 1px solid #999999;" onclick="javascript:hide_or_show('backlinks');"></span>Backlinks (<%=
299
+ # @google_results.size -%>)
300
+ # <%- end -%>
301
+ #
302
+ def legend_block(&block)
303
+ concat content_tag(:div, capture(&block), :class => "faux_legend")
304
+ end
305
+
306
+ # DRY way to return a legend tag that renders correctly in all browsers
307
+ #
308
+ # Sample usage:
309
+ #
310
+ # <%= legend_tag "Report Criteria" -%>
311
+ #
312
+ # Sample usage with help text:
313
+ #
314
+ # <%= legend_tag "Report Criteria", :help => "Some descriptive copy here." -%>
315
+ # <span id="hide_or_show_backlinks" class="show_link" style="background-color: #999999;
316
+ # border: 1px solid #999999;" onclick="javascript:hide_or_show('backlinks');"></span>Backlinks (<%=
317
+ # @google_results.size -%>)
318
+ # <%- end -%>
319
+ #
320
+ # Recommended CSS to support display of help icon and text:
321
+ #
322
+ # .help_icon {
323
+ # display: block;
324
+ # float: left;
325
+ # margin-top: -16px;
326
+ # margin-left: 290px;
327
+ # border-left: 1px solid #444444;
328
+ # padding: 3px 6px;
329
+ # cursor: pointer;
330
+ # }
331
+ #
332
+ # div.popup_help {
333
+ # color: #666666;
334
+ # width: 98%;
335
+ # background: #ffffff;
336
+ # padding: 1em;
337
+ # border: 1px solid #999999;
338
+ # margin: 1em 0em;
339
+ # }
340
+ #
341
+ def legend_tag(text, args={})
342
+ args[:id] ||= text.downcase.gsub(/ /,'_')
343
+ if args[:help]
344
+ _html = %{<div id="#{args[:id]}" class="faux_legend">#{text}<span class="help_icon" onclick="$('#{args[:id]}_help').toggle();">?</span></div>\r}
345
+ _html << %{<div id="#{args[:id]}_help" class="popup_help" style="display: none;">#{args[:help]}<br /></div>\r}
346
+ else
347
+ _html = %{<div id="#{args[:id]}" class="faux_legend">#{text}</div>\r}
348
+ end
349
+ _html.gsub!(/ id=""/,'')
350
+ _html.gsub!(/ class=""/,'')
351
+ _html
352
+ end
353
+
354
+ def meta_description(content=nil)
355
+ content_for(:meta_description) { content } unless content.blank?
356
+ end
357
+
358
+ def meta_keywords(content=nil)
359
+ content_for(:meta_keywords) { content } unless content.blank?
360
+ end
361
+
362
+ def models_for_select( models, label = 'name' )
363
+ models.map{ |m| [m[label], m.id] }.sort_by{ |e| e[0] }
364
+ end
365
+
366
+ def options_for_array( a, selected = nil, prompt = SELECT_PROMPT )
367
+ "<option value=''>#{prompt}</option>" + a.map{ |_e| _flag = _e[0].to_s == selected ? 'selected="1"' : ''; _e.is_a?(Array) ? "<option value=\"#{_e[0]}\" #{_flag}>#{_e[1]}</option>" : "<option>#{_e}</option>" }.to_s
368
+ end
369
+
370
+ # Create a link that is opaque to search engine spiders.
371
+ def obfuscated_link_to(path, image, label, args={})
372
+ _html = %{<form action="#{path}" method="get" class="obfuscated_link">}
373
+ _html << %{ <fieldset><input alt="#{label}" src="#{image}" type="image" /></fieldset>}
374
+ args.each{ |k,v| _html << %{ <div><input id="#{k.to_s}" name="#{k}" type="hidden" value="#{v}" /></div>} }
375
+ _html << %{</form>}
376
+ _html
377
+ end
378
+
379
+ # Wraps the given HTML in Rails' default style to highlight validation errors, if any.
380
+ def required_field_helper( model, element, html )
381
+ if model && ! model.errors.empty? && element.is_required
382
+ return content_tag( :div, html, :class => 'fieldWithErrors' )
383
+ else
384
+ return html
385
+ end
386
+ end
387
+
388
+ # Use on index pages to create dropdown list of filtering criteria.
389
+ # Populate the filter list using a constant in the model corresponding to named scopes.
390
+ #
391
+ # Usage:
392
+ #
393
+ # - item.rb:
394
+ #
395
+ # named_scope :active, :conditions => { :is_active => true }
396
+ # named_scope :inactive, :conditions => { :is_active => false }
397
+ #
398
+ # FILTERS = [
399
+ # {:scope => "all", :label => "All"},
400
+ # {:scope => "active", :label => "Active Only"},
401
+ # {:scope => "inactive", :label => "Inactive Only"}
402
+ # ]
403
+ #
404
+ # - items/index.html.erb:
405
+ #
406
+ # <%= select_tag_for_filter("items", @filters, params) -%>
407
+ #
408
+ # - items_controller.rb:
409
+ #
410
+ # def index
411
+ # @filters = Item::FILTERS
412
+ # if params[:show] && params[:show] != "all" && @filters.collect{|f| f[:scope]}.include?(params[:show])
413
+ # @items = eval("@items.#{params[:show]}.order_by(params[:by], params[:dir])")
414
+ # else
415
+ # @items = @items.order_by(params[:by], params[:dir])
416
+ # end
417
+ # ...
418
+ # end
419
+ #
420
+ def select_tag_for_filter(model, filters, params)
421
+ return unless model && ! filters.blank?
422
+
423
+ # capture and delete previous show param
424
+ _old_show = params.delete :show
425
+
426
+ _html = %{Show&nbsp;&nbsp;<select name="show" id="show" onchange="window.location='#{eval("#{model}_url")}?#{params.to_params}&show=' + this.value">}
427
+
428
+ # restore previous show param
429
+ params[:show] = _old_show
430
+
431
+ filters.each do |pair|
432
+ _html = %{#{_html}<option value="#{pair[:scope]}"}
433
+ _html = %{#{_html} selected="selected"} if params[:show] == pair[:scope]
434
+ _html = %{#{_html}>#{pair[:label]}</option>}
435
+ end
436
+
437
+ _html = %{#{_html}</select>}
438
+ end
439
+
440
+ # Returns a link_to tag with sorting parameters that can be used with ActiveRecord.order_by.
441
+ #
442
+ # To use standard resources, specify the resources as a plural symbol:
443
+ # sort_link(:users, 'email', params)
444
+ #
445
+ # To use resources aliased with :as (in routes.rb), specify the aliased route as a string.
446
+ # sort_link('users_admin', 'email', params)
447
+ #
448
+ # You can override the link's label by adding a labels hash to your params in the controller:
449
+ # params[:labels] = {'user_id' => 'User'}
450
+ def sort_link(model, field, params, html_options={})
451
+ if (field.to_sym == params[:by] || field == params[:by]) && params[:dir] == "ASC"
452
+ classname = "arrow-asc"
453
+ dir = "DESC"
454
+ elsif (field.to_sym == params[:by] || field == params[:by])
455
+ classname = "arrow-desc"
456
+ dir = "ASC"
457
+ else
458
+ dir = "ASC"
459
+ end
460
+
461
+ options = {
462
+ :anchor => html_options[:anchor],
463
+ :by => field,
464
+ :dir => dir,
465
+ :query => params[:query],
466
+ :show => params[:show]
467
+ }
468
+
469
+ options[:show] = params[:show] unless params[:show].blank? || params[:show] == 'all'
470
+
471
+ html_options = {
472
+ :class => "#{classname} #{html_options[:class]}",
473
+ :style => "color: white; font-weight: #{params[:by] == field ? "bold" : "normal"}; #{html_options[:style]}",
474
+ :title => "Sort by this field"
475
+ }
476
+
477
+ field_name = params[:labels] && params[:labels][field] ? params[:labels][field] : field.titleize
478
+
479
+ _link = model.is_a?(Symbol) ? eval("#{model}_url(options)") : "/#{model}?#{options.to_params}"
480
+ link_to(field_name, _link, html_options)
481
+ end
482
+
483
+ # Tabbed interface helpers =======================================================================
484
+
485
+ # Returns formatted tabs with appropriate JS for activation. Use in conjunction with tab_body.
486
+ #
487
+ # Usage:
488
+ #
489
+ # <%- tabset do -%>
490
+ # <%= tab_tag :id => 'ppc_ads', :label => 'PPC Ads', :state => 'active' %>
491
+ # <%= tab_tag :id => 'budget' %>
492
+ # <%= tab_tag :id => 'geotargeting' %>
493
+ # <%- end -%>
494
+ #
495
+ def tabset(&proc)
496
+ concat %{
497
+ <div class="jump_links">
498
+ <ul>
499
+ }
500
+ yield
501
+ concat %{
502
+ </ul>
503
+ </div>
504
+ <br style="clear: both;" /><br />
505
+ <input type="hidden" id="show_tab" />
506
+ <script type="text/javascript">
507
+ function hide_all_tabs() { $$('.tab_block').invoke('hide'); }
508
+ function activate_tab(tab) {
509
+ $$('.tab_control').each(function(elem){ elem.className = 'tab_control'});
510
+ $('show_' + tab).className = 'tab_control active';
511
+ hide_all_tabs();
512
+ $(tab).toggle();
513
+ $('show_tab').value = tab
514
+ }
515
+ function sticky_tab() { if (location.hash) { activate_tab(location.hash.gsub('#','')); } }
516
+ Event.observe(window, 'load', function() { sticky_tab(); });
517
+ </script>
518
+ }
519
+ end
520
+
521
+ # Returns a tab body corresponding to tabs in a tabset. Make sure that the id of the tab_body
522
+ # matches the id provided to the tab_tag in the tabset block.
523
+ #
524
+ # Usage:
525
+ #
526
+ # <%- tab_body :id => 'ppc_ads', :label => 'PPC Ad Details' do -%>
527
+ # PPC ads form here.
528
+ # <%- end -%>
529
+ #
530
+ # <%- tab_body :id => 'budget' do -%>
531
+ # Budget form here.
532
+ # <%- end -%>
533
+ #
534
+ # <%- tab_body :id => 'geotargeting' do -%>
535
+ # Geotargeting form here.
536
+ # <%- end -%>
537
+ #
538
+ def tab_body(args, &proc)
539
+ concat %{<div id="#{args[:id]}" class="tab_block form_container" style="display: #{args[:display] || 'none'};">}
540
+ concat %{#{legend_tag args[:label] || args[:id].titleize }}
541
+ concat %{<a name="#{args[:id]}"></a><br />}
542
+ yield
543
+ concat %{</div>}
544
+ end
545
+
546
+ # Returns the necessary HTML for a particular tab. Use inside a tabset block.
547
+ # Override the default tab label by specifying a :label parameter.
548
+ # Indicate that the tab should be active by setting its :state to 'active'.
549
+ # (NOTE: You must define a corresponding CSS style for active tabs.)
550
+ #
551
+ # Usage:
552
+ #
553
+ # <%= tab_tag :id => 'ppc_ads', :label => 'PPC Ads', :state => 'active' %>
554
+ #
555
+ def tab_tag(args, *css_class)
556
+ %{<li id="show_#{args[:id]}" class="tab_control #{args[:state]}" onclick="window.location='##{args[:id]}'; activate_tab('#{args[:id]}');">#{args[:label] || args[:id].to_s.titleize}</li>}
557
+ end
558
+
559
+ # ================================================================================================
560
+
561
+ def tag_for_collapsible_row(obj, params)
562
+ _html = ""
563
+ if obj && obj.respond_to?(:parent) && obj.parent
564
+ _html << %{<tr class="#{obj.class.name.downcase}_#{obj.parent.id} #{params[:class]}" style="display: none; #{params[:style]}">}
565
+ else
566
+ _html << %{<tr class="#{params[:class]}" style="#{params[:style]}">}
567
+ end
568
+ _html
569
+ end
570
+
571
+ def tag_for_collapsible_row_control(obj)
572
+ _base_id = "#{obj.class.name.downcase}_#{obj.id}"
573
+ _html = %{<div id="hide_or_show_#{_base_id}" class="show_link" style="background-color: #999999; border: 1px solid #999999;" onclick="javascript:hide_or_show('#{_base_id}');"></div>}
574
+ end
575
+
576
+ # Create a set of tags for displaying a field label with inline help.
577
+ # Field label text is appended with a ? icon, which responds to a click
578
+ # by showing or hiding the provided help text.
579
+ #
580
+ # Sample usage:
581
+ #
582
+ # <%= tag_for_label_with_inline_help 'Relative Frequency', 'rel_frequency', 'Relative frequency of search traffic for this keyword across multiple search engines, as measured by WordTracker.' %>
583
+ #
584
+ # Yields:
585
+ #
586
+ # <label for="rel_frequency">Relative Frequency: <%= image_tag "/images/help_icon.png", :onclick => "$('rel_frequency_help').toggle();", :class => 'inline_icon' %></label><br />
587
+ # <div class="inline_help" id="rel_frequency_help" style="display: none;">
588
+ # <p>Relative frequency of search traffic for this keyword across multiple search engines, as measured by WordTracker.</p>
589
+ # </div>
590
+ def tag_for_label_with_inline_help( label_text, field_id, help_text )
591
+ _html = ""
592
+ _html << %{<label for="#{field_id}">#{label_text}}
593
+ _html << %{<img src="/images/icons/help_icon.png" onclick="$('#{field_id}_help').toggle();" class='inline_icon' />}
594
+ _html << %{</label><br />}
595
+ _html << %{<div class="inline_help" id="#{field_id}_help" style="display: none;">}
596
+ _html << %{<p>#{help_text}</p>}
597
+ _html << %{</div>}
598
+ _html
599
+ end
600
+
601
+ # Create a set of tags for displaying a field label followed by instructions.
602
+ # The instructions are displayed on a new line following the field label.
603
+ #
604
+ # Usage:
605
+ #
606
+ # <%= tag_for_label_with_instructions 'Status', 'is_active', 'Only active widgets will be visible to the public.' %>
607
+ #
608
+ # Yields:
609
+ #
610
+ # <label for="is_active">
611
+ # Status<br />
612
+ # <span class="instructions">Only active widgets will be visible to the public.</span>
613
+ # <label><br />
614
+ def tag_for_label_with_instructions( label_text, field_id, instructions )
615
+ _html = ""
616
+ _html << %{<label for="#{field_id}">#{label_text}}
617
+ _html << %{<span class="instructions">#{instructions}</span>}
618
+ _html << %{</label><br />}
619
+ _html
620
+ end
621
+
622
+ end
623
+
624
+ class Array
625
+ def mean
626
+ self.inject(0){ |sum, x| sum += x } / self.size.to_f
627
+ end
628
+
629
+ def count
630
+ self.size
631
+ end
632
+
633
+ end
634
+
635
+ module Enumerable
636
+ def to_histogram
637
+ inject(Hash.new(0)) { |h,x| h[x] += 1; h }
638
+ end
639
+ end
640
+
641
+ class Fixnum
642
+ include MirUtility
643
+
644
+ # Given a number of seconds, convert into a string like HH:MM:SS
645
+ def to_hrs_mins_secs
646
+ _now = DateTime.now
647
+ _d = Date::day_fraction_to_time((_now + self.seconds) - _now)
648
+ "#{sprintf('%02d',_d[0])}:#{sprintf('%02d',_d[1])}:#{sprintf('%02d',_d[2])}"
649
+ end
650
+ end
651
+
652
+ class Float
653
+ include MirUtility
654
+ def to_nearest_tenth
655
+ sprintf("%.1f", self).to_f
656
+ end
657
+ end
658
+
659
+ class Hash
660
+ def to_params
661
+ params = ''
662
+ stack = []
663
+
664
+ each do |k, v|
665
+ if v.is_a?(Hash)
666
+ stack << [k,v]
667
+ elsif v.is_a?(Array)
668
+ stack << [k,Hash.from_array(v)]
669
+ else
670
+ params << "#{k}=#{v}&"
671
+ end
672
+ end
673
+
674
+ stack.each do |parent, hash|
675
+ hash.each do |k, v|
676
+ if v.is_a?(Hash)
677
+ stack << ["#{parent}[#{k}]", v]
678
+ else
679
+ params << "#{parent}[#{k}]=#{v}&"
680
+ end
681
+ end
682
+ end
683
+
684
+ params.chop!
685
+ params
686
+ end
687
+
688
+ def to_sql( operator = 'AND' )
689
+ _sql = self.keys.map do |_key|
690
+ _value = self[_key].is_a?(Fixnum) ? self[_key] : "'#{self[_key]}'"
691
+ self[_key].nil? ? '1 = 1' : "#{_key} = #{_value}"
692
+ end
693
+ _sql * " #{operator} "
694
+ end
695
+
696
+ def self.from_array(array = [])
697
+ h = Hash.new
698
+ array.size.times{ |t| h[t] = array[t] }
699
+ h
700
+ end
701
+
702
+ end
703
+
704
+ # Helper class for SOAP headers.
705
+ class Header < SOAP::Header::SimpleHandler
706
+ def initialize(tag, value)
707
+ super(XSD::QName.new(nil, tag))
708
+ @tag = tag
709
+ @value = value
710
+ end
711
+
712
+ def on_simple_outbound
713
+ @value
714
+ end
715
+ end
716
+
717
+ class String
718
+
719
+ # Bring in support for view helpers
720
+ include MirUtility::CoreExtensions::String::NumberHelper
721
+
722
+ # General methods
723
+
724
+ def capitalize_words
725
+ self.downcase.gsub(/\b([a-z])/) { $1.capitalize }.gsub( "'S", "'s" )
726
+ end
727
+
728
+ # Address methods
729
+
730
+ def expand_address_abbreviations
731
+ _address = self.strip.capitalize_words
732
+
733
+ # NOTE: DO NOT rearrange the replace sequences; order matters!
734
+
735
+ # streets
736
+ _address.gsub!( /\b(ave|av)\.?\b/i, 'Avenue ' )
737
+ _address.gsub!( /\b(blvd|blv|bld|bl)\.?\b/i, 'Boulevard ' )
738
+ _address.gsub!( /\bcr\.?\b/i, 'Circle ' )
739
+ _address.gsub!( /\bctr\.?\b/i, 'Center ' )
740
+ _address.gsub!( /\b(crt|ct)\.?\b/i, 'Court ' )
741
+ _address.gsub!( /\bdr\.?\b/i, 'Drive ' )
742
+ _address.gsub!( /\b(expressw|expw|expy)\.?\b/i, 'Expressway ' )
743
+ _address.gsub!( /\bfrwy\.?\b/i, 'Freeway ' )
744
+ _address.gsub!( /\bhwy\.?\b/i, 'Highway ' )
745
+ _address.gsub!( /\bln\.?\b/i, 'Lane ' )
746
+ _address.gsub!( /\b(prkwy|pkwy|pkw|pky)\.?\b/i, 'Parkway ' )
747
+ _address.gsub!( /\bpk\.?\b/i, 'Pike ' )
748
+ _address.gsub!( /\bplz\.?\b/i, 'Plaza ' )
749
+ _address.gsub!( /\bpl\.?\b/i, 'Place ' )
750
+ _address.gsub!( /\brd\.?\b/i, 'Road ' )
751
+ _address.gsub!( /\b(rte|rt)\.?\b/i, 'Route ' )
752
+ _address.gsub!( /\bste\.?\b/i, 'Suite ' )
753
+ _address.gsub!( /\bst\.?\b/i, 'Street ' )
754
+ _address.gsub!( /\btrpk\.?\b/i, 'Turnpike ' )
755
+ _address.gsub!( /\btr\.?\b/i, 'Trail ' )
756
+
757
+ # directions
758
+ _address.gsub!( /\bN\.?e\.?\b/i, 'Northeast ' )
759
+ _address.gsub!( /\bS\.?e\.?\b/i, 'Southeast ' )
760
+ _address.gsub!( /\bS\.?w\.?\b/i, 'Southwest ' )
761
+ _address.gsub!( /\bN\.?w\.?\b/i, 'Northwest ' )
762
+ _address.gsub!( /\bN\.?\b/, 'North ' )
763
+ _address.gsub!( /\bE\.?\b/, 'East ' )
764
+ _address.gsub!( /\bS\.?\b/, 'South ' )
765
+ _address.gsub!( /\bW\.?\b/, 'West ' )
766
+ _address.gsub!( '.', '' )
767
+ _address.gsub!( / +/, ' ' )
768
+ _address.strip
769
+ end
770
+
771
+ def formatted_phone
772
+ if self
773
+ # remove non-digit characters
774
+ _self = self.gsub(/[\(\) -]+/, '')
775
+ # format as phone if 10 digits are left
776
+ return number_to_phone(_self, :area_code => true ) if !! (_self =~ /[0-9]{10}/)
777
+ end
778
+
779
+ self
780
+ end
781
+
782
+ def formatted_zip
783
+ return if self.blank?
784
+ self.gsub!( /[\(\) -]+/, '' )
785
+ self.size == 9 ? "#{self[0 .. 4]}-#{self[5 .. -1]}" : self
786
+ end
787
+
788
+ # Time methods
789
+
790
+ def to_12_hour_time
791
+ (self == '0' || self.blank?) ? nil : Time.parse( "#{self[0..-3]}:#{self[-2..-1]}" ).to_s( :time ).gsub(/^0/, '')
792
+ end
793
+
794
+ # URL methods
795
+
796
+ # Prefixes the given url with 'http://'.
797
+ def add_http_prefix
798
+ return if self.blank?
799
+ _uri = self.to_uri
800
+ return self if _uri.nil? || _uri.is_a?(URI::FTP) || _uri.is_a?(URI::HTTP) || _uri.is_a?(URI::HTTPS) || _uri.is_a?(URI::LDAP) || _uri.is_a?(URI::MailTo)
801
+ "http://#{self}"
802
+ end
803
+
804
+ # Returns true if a given string begins with http:// or https://.
805
+ def has_http?
806
+ !! (self =~ /^http[s]?:\/\/.+/)
807
+ end
808
+
809
+ # Returns true if a given string has a trailing slash.
810
+ def has_trailing_slash?
811
+ !! (self =~ /\/$/)
812
+ end
813
+
814
+ # Returns true if a given string refers to an HTML page.
815
+ def is_page?
816
+ !! (self =~ /\.htm[l]?$/)
817
+ end
818
+
819
+ # Returns the host from a given URL string; returns nil if the string is not a valid URL.
820
+ def to_host
821
+ _uri = self.to_uri
822
+ _uri ? _uri.host : nil
823
+ end
824
+
825
+ # Returns a URI for the given string; nil if the string is invalid.
826
+ def to_uri
827
+ begin
828
+ _uri = URI.parse self
829
+ rescue URI::InvalidURIError
830
+ RAILS_DEFAULT_LOGGER.warn "#{self} is an invalid URI!"
831
+ end
832
+
833
+ _uri
834
+ end
835
+
836
+ # Returns true if the given string is a valid URL.
837
+ def valid_http_url?
838
+ self.scan(/:\/\//).size == 1 && self.to_uri.is_a?(URI::HTTP)
839
+ end
840
+ end
841
+
842
+ class StringHelperSingleton
843
+ include Singleton
844
+ include ActionView::Helpers::NumberHelper
845
+ end
846
+
847
+ class TrueClass
848
+ def to_i; 1; end
849
+ end
850
+
851
+ class FalseClass
852
+ def to_i; 0; end
853
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{mir_utility}
5
+ s.version = "0.3.29"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Corey Ehmke and Rod Monje"]
9
+ s.date = %q{2010-10-21}
10
+ s.description = %q{Standard extensions for Mir Rails apps.}
11
+ s.email = %q{corey@seologic.com}
12
+ s.extra_rdoc_files = ["README.rdoc", "lib/mir_form_builder.rb", "lib/mir_utility.rb"]
13
+ s.files = ["Manifest", "README.rdoc", "Rakefile", "init.rb", "lib/mir_form_builder.rb", "lib/mir_utility.rb", "mir_utility.gemspec"]
14
+ s.homepage = %q{http://github.com/bantik/mir_utility}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Mir_utility", "--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{mir_utility}
18
+ s.rubygems_version = %q{1.3.7}
19
+ s.summary = %q{Standard extensions for Mir Rails apps.}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 3
24
+
25
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
+ else
27
+ end
28
+ else
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mir_utility
3
+ version: !ruby/object:Gem::Version
4
+ hash: 41
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 29
10
+ version: 0.3.29
11
+ platform: ruby
12
+ authors:
13
+ - Corey Ehmke and Rod Monje
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-21 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Standard extensions for Mir Rails apps.
23
+ email: corey@seologic.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.rdoc
30
+ - lib/mir_form_builder.rb
31
+ - lib/mir_utility.rb
32
+ files:
33
+ - Manifest
34
+ - README.rdoc
35
+ - Rakefile
36
+ - init.rb
37
+ - lib/mir_form_builder.rb
38
+ - lib/mir_utility.rb
39
+ - mir_utility.gemspec
40
+ has_rdoc: true
41
+ homepage: http://github.com/bantik/mir_utility
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options:
46
+ - --line-numbers
47
+ - --inline-source
48
+ - --title
49
+ - Mir_utility
50
+ - --main
51
+ - README.rdoc
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 11
69
+ segments:
70
+ - 1
71
+ - 2
72
+ version: "1.2"
73
+ requirements: []
74
+
75
+ rubyforge_project: mir_utility
76
+ rubygems_version: 1.3.7
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Standard extensions for Mir Rails apps.
80
+ test_files: []
81
+