mir_utility 0.3.29

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,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
+