diff --git a/Gemfile b/Gemfile index a2bf80e20..da4b75286 100644 --- a/Gemfile +++ b/Gemfile @@ -19,6 +19,7 @@ gem 'json' gem 'mechanize' gem 'mysql' gem 'nokogiri' +gem 'protected_attributes' # remove once we migrate to Strong Parameters gem 'rails', '4.2.6' # 4 gem 'rake' gem 'ruport' @@ -65,6 +66,8 @@ group :development, :test do gem 'sdoc', '~> 0.4.0' gem 'rspec-rails' gem 'simplecov' + gem 'spring' gem 'sqlite3' gem 'timecop' + gem 'web-console', '~> 2.0' end diff --git a/Gemfile.lock b/Gemfile.lock index c6aac990b..ca9089fba 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -123,6 +123,7 @@ GEM temple (>= 0.8.0) tilt hashery (2.1.2) + hominid (3.0.5) http-cookie (1.0.3) domain_name (~> 0.5) i18n (0.8.4) @@ -183,6 +184,8 @@ GEM prawn (0.12.0) pdf-reader (>= 0.9.0) ttfunk (~> 1.0.2) + protected_attributes (1.1.3) + activemodel (>= 4.0.1, < 5.0) public_suffix (2.0.5) rack (1.6.8) rack-test (0.6.3) @@ -327,6 +330,7 @@ DEPENDENCIES faye-websocket figaro haml + hominid i18n jbuilder (~> 2.0) jquery-rails @@ -338,6 +342,7 @@ DEPENDENCIES mysql nokogiri poltergeist + protected_attributes rack-test rails (= 4.2.6) rake diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 58de27e52..00cc072f3 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -17,7 +17,6 @@ class ApplicationController < ActionController::Base require 'csv.rb' require 'string_extras.rb' - require 'date_time_extras.rb' # Session keys # :cid id of logged in user; if absent, nobody logged in diff --git a/app/helpers/javascript_tag_helper.rb b/app/helpers/javascript_tag_helper.rb deleted file mode 100644 index ca8060af4..000000000 --- a/app/helpers/javascript_tag_helper.rb +++ /dev/null @@ -1,13 +0,0 @@ -module JavascriptTagHelper - ## Load jQuery, rails.js, and everything in the Javascript dir. - ## Obsoleted by asset pipeline in Rails 3 - - def javascript_include_tag_for_jquery(*args) - default_files = %w(jquery.min jquery-ui.min rails application) - other_files = Dir["#{ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR}/*.js"]. - map { |s| File.basename(s).gsub(/\.js$/,'') }. - delete_if { |s| default_files.include? s } - javascript_include_tag(default_files, :cache => 'jquery') << "\n" << - javascript_include_tag(other_files, :cache => 'a1') - end -end diff --git a/app/models/auto_importer.rb b/app/models/auto_importer.rb index b426ce0ec..fda0403af 100644 --- a/app/models/auto_importer.rb +++ b/app/models/auto_importer.rb @@ -1,6 +1,3 @@ -require 'date_time_extras' -require 'string_extras' - class AutoImporter attr_accessor :import, :messages, :email diff --git a/app/models/customer.rb b/app/models/customer.rb index 02850ccfb..83c6c2822 100644 --- a/app/models/customer.rb +++ b/app/models/customer.rb @@ -6,7 +6,6 @@ class Customer < ActiveRecord::Base require_dependency 'customer/scopes' require_dependency 'customer/birthday' require_dependency 'customer/merge' - require_dependency '../lib/date_time_extras' include Authentication include Authentication::ByPassword diff --git a/app/models/customer/scopes.rb b/app/models/customer/scopes.rb index 51a43f1ba..378071112 100644 --- a/app/models/customer/scopes.rb +++ b/app/models/customer/scopes.rb @@ -1,51 +1,41 @@ class Customer < ActiveRecord::Base - default_scope :order => 'last_name, zip' + default_scope { order('last_name, zip') } + scope :subscriber_during, ->(seasons) { + joins(:vouchertypes).where('vouchertypes.subscription = ? AND vouchertypes.season IN (?)', true, seasons) + } - named_scope :subscriber_during, lambda { |seasons| - { :joins => :vouchertypes, - :conditions => ['vouchertypes.subscription = ? AND vouchertypes.season IN (?)', - true, seasons] }} - - - named_scope :purchased_any_vouchertypes, lambda { |vouchertype_ids| - { :joins => :vouchertypes, - :conditions => ['vouchertypes.id IN (?)', vouchertype_ids], - :select => 'DISTINCT customers.*'}} + scope :purchased_any_vouchertypes, ->(vouchertype_ids) { + joins(:vouchertypes).where('vouchertypes.id IN (?)', vouchertype_ids).select('distinct customers.*') + } def self.purchased_no_vouchertypes(vouchertype_ids) Customer.all - Customer.purchased_any_vouchertypes(vouchertype_ids) end - - named_scope :seen_any_of, lambda { |show_ids| - { :joins => [:vouchers,:showdates], - :conditions => ['items.customer_id = customers.id AND - items.showdate_id = showdates.id AND - items.type = "Voucher" AND - showdates.show_id IN (?)', show_ids], - :select => 'DISTINCT customers.*' - }} + scope :seen_any_of, ->(show_ids) { + joins(:vouchers, :showdates). + where('items.customer_id = customers.id AND items.showdate_id = showdates.id AND + items.type = "Voucher" AND showdates.show_id IN (?)', show_ids). + select('DISTINCT customers.*') + } + def self.seen_none_of(show_ids) ; Customer.all - Customer.seen_any_of(show_ids) ; end - named_scope :with_open_subscriber_vouchers, lambda { |vtypes| - { :joins => ',items', - :conditions => ['items.customer_id = customers.id AND - items.type = "Voucher" AND + scope :with_open_subscriber_vouchers, ->(vtypes) { + joins(:items). + where('items.customer_id = customers.id AND items.type = "Voucher" AND (items.showdate_id = 0 OR items.showdate_id IS NULL) AND - items.vouchertype_id IN (?)', vtypes], - :select => 'DISTINCT customers.*' - }} - - - named_scope :donated_during, lambda { |start_date, end_date, amount| - { :joins => ',items,orders', - :select => 'DISTINCT customers.*', - :conditions => ['items.customer_id = customers.id AND - items.amount >= ? AND - items.type = "Donation" AND - orders.sold_on BETWEEN ? AND ?', - amount, start_date, end_date] }} - + items.vouchertype_id IN (?)', vtypes). + select('DISTINCT customers.*') + } + + scope :donated_during, ->(start_date, end_date, amount) { + joins(:items, :orders). + where(%q{items.customer_id = customers.id AND items.amount >= ? AND items.type = "Donation" + AND orders.sold_on BETWEEN ? AND ?}, + amount, start_date, end_date). + select('distinct customers.*') + } end diff --git a/app/models/show.rb b/app/models/show.rb index b690e326e..836997936 100644 --- a/app/models/show.rb +++ b/app/models/show.rb @@ -30,12 +30,11 @@ def self.current_or_next Showdate.current_or_next.try(:show) end - named_scope :current_and_future, lambda { - {:joins => :showdates, - :select => 'DISTINCT shows.*', - :conditions => ['showdates.thedate >= ?', 1.day.ago], - :order => 'opening_date ASC' - } + scope :current_and_future, -> { + joins(:showdates). + where('showdates.thedate >= ?', 1.day.ago). + select('DISTINCT shows.*'). + order('opening_date ASC') } def has_showdates? ; !showdates.empty? ; end @@ -60,9 +59,9 @@ def self.all_for_season(season=Time.this_season) :include => :showdates) end - named_scope :all_for_seasons, lambda { |from,to| - {:conditions => ['opening_date BETWEEN ? AND ?', - Time.at_beginning_of_season(from), Time.at_end_of_season(to)] } + scope :all_for_seasons, ->(from,to) { + where('opening_date BETWEEN ? AND ?', + Time.at_beginning_of_season(from), Time.at_end_of_season(to)) } def self.seasons_range @@ -77,8 +76,8 @@ def self.type(arg) TYPES.include?(arg) ? arg : REGULAR_SHOW end - named_scope :of_type, lambda { |type| - {:conditions => ["event_type = ?", self.type(type) ] } + scope :of_type, ->(type) { + where('event_type = ?', self.type(type)) } def season diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 4d102e766..7fb447d4a 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -8,16 +8,14 @@ = stylesheet_link_tag 'admin', :media => 'all' = stylesheet_link_tag 'venue/default', :media => 'all' - -# Rails3: no need to redefine default JS files in javascript_tag_helper.rb - = javascript_include_tag_for_jquery :all + = javascript_include_tag 'application' %script{:type => 'text/javascript', :src => 'https://js.stripe.com/v1'} %title= @page_title || h(controller.action_name.humanize) %meta{'http-equiv'=>'content-type', :content=>'text/html; charset=utf-8'}/ %meta{:name=>:description, :content=>''}/ - -# Rails3 provides the following 2 lines via csrf_meta_tag helper - %meta{:name => 'csrf-param', :content => Rack::Utils.escape_html(request_forgery_protection_token)} - %meta{:name => 'csrf-token', :content => Rack::Utils.escape_html(form_authenticity_token)} + + = csrf_meta_tags %body{:id=>"#{controller.controller_name}_#{controller.action_name}", :class=>(Figaro.env.sandbox ? 'testing.default' : 'default')} diff --git a/bin/bundle b/bin/bundle new file mode 100755 index 000000000..66e9889e8 --- /dev/null +++ b/bin/bundle @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +load Gem.bin_path('bundler', 'bundle') diff --git a/bin/rails b/bin/rails new file mode 100755 index 000000000..0138d79b7 --- /dev/null +++ b/bin/rails @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby +begin + load File.expand_path('../spring', __FILE__) +rescue LoadError => e + raise unless e.message.include?('spring') +end +APP_PATH = File.expand_path('../../config/application', __FILE__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/bin/rake b/bin/rake new file mode 100755 index 000000000..d87d5f578 --- /dev/null +++ b/bin/rake @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby +begin + load File.expand_path('../spring', __FILE__) +rescue LoadError => e + raise unless e.message.include?('spring') +end +require_relative '../config/boot' +require 'rake' +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 000000000..acdb2c138 --- /dev/null +++ b/bin/setup @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +require 'pathname' + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) + +Dir.chdir APP_ROOT do + # This script is a starting point to setup your application. + # Add necessary setup steps to this file: + + puts "== Installing dependencies ==" + system "gem install bundler --conservative" + system "bundle check || bundle install" + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # system "cp config/database.yml.sample config/database.yml" + # end + + puts "\n== Preparing database ==" + system "bin/rake db:setup" + + puts "\n== Removing old logs and tempfiles ==" + system "rm -f log/*" + system "rm -rf tmp/cache" + + puts "\n== Restarting application server ==" + system "touch tmp/restart.txt" +end diff --git a/bin/spring b/bin/spring new file mode 100755 index 000000000..fb2ec2ebb --- /dev/null +++ b/bin/spring @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby + +# This file loads spring without using Bundler, in order to be fast. +# It gets overwritten when you run the `spring binstub` command. + +unless defined?(Spring) + require 'rubygems' + require 'bundler' + + lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read) + spring = lockfile.specs.detect { |spec| spec.name == "spring" } + if spring + Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path + gem 'spring', spring.version + require 'spring/binstub' + end +end diff --git a/config.ru b/config.ru new file mode 100644 index 000000000..bd83b2541 --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment', __FILE__) +run Rails.application diff --git a/config/application.rb b/config/application.rb index 6c02d5ffe..7addac9b1 100644 --- a/config/application.rb +++ b/config/application.rb @@ -31,9 +31,12 @@ class Application < Rails::Application # Do not swallow errors in after_commit/after_rollback callbacks. config.active_record.raise_in_transactional_callbacks = true - # Use Rspec - config.generators do |g| - g.test_framework :rspec + config.autoload_paths << Rails.root.join('lib') + + config.after_initialize do + Time.include CoreExtensions::Time::Season + Date.include CoreExtensions::Date::Season + String.include CoreExtensions::String::Name end end end diff --git a/config/environment.rb b/config/environment.rb index d1fef00d4..1eb14a34e 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -5,28 +5,6 @@ Rails.application.configure do - # Only load the plugins named here, in the order given (default is alphabetical). - # :all can be used as a placeholder for all plugins not explicitly named - # config.plugins = [ :exception_notification, :ssl_requirement, :all ] - - # Skip frameworks you're not going to use. To use Rails without a database, - # you must remove the Active Record framework. - # config.frameworks -= [ :active_record, :active_resource, :action_mailer ] - - # Activate observers that should always be running - # config.active_record.observers = :cacher, :garbage_collector, :forum_observer - - # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. - # Run "rake -D time" for a list of tasks for finding time zone names. - # config.time_zone = 'UTC' - - # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. - # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')] - # config.i18n.default_locale = :de - # session key name - config.action_controller.session_store = :active_record_store - #ActionController::Base.session_options[:session_key] = 'audience1st_session_id' - config.after_initialize do config.action_mailer.delivery_method = :test if Figaro.env.sandbox end diff --git a/config/initializers/errors_as_html.rb b/config/initializers/errors_as_html.rb index df2666f88..09f60be78 100644 --- a/config/initializers/errors_as_html.rb +++ b/config/initializers/errors_as_html.rb @@ -1,5 +1,4 @@ -# rails3 this will become ActiveModel::Base -class ActiveRecord::Base +class ActiveModel::Base def errors_as_html(sep = '
') errors.full_messages.join(sep) end diff --git a/db/migrate/20130503193126_add_valid_vouchers_for_bundles.rb b/db/migrate/20130503193126_add_valid_vouchers_for_bundles.rb index 0fb32d5d7..d69693b8d 100644 --- a/db/migrate/20130503193126_add_valid_vouchers_for_bundles.rb +++ b/db/migrate/20130503193126_add_valid_vouchers_for_bundles.rb @@ -1,4 +1,3 @@ -require 'lib/date_time_extras' class AddValidVouchersForBundles < ActiveRecord::Migration def self.up # for each Bundle voucher, add a valid-voucher that enables it diff --git a/lib/core_extensions/date/season.rb b/lib/core_extensions/date/season.rb new file mode 100644 index 000000000..22fcb49f2 --- /dev/null +++ b/lib/core_extensions/date/season.rb @@ -0,0 +1,22 @@ +module CoreExtensions + module Date + module Season + def self.included(base) ; base.extend(ClassMethods) ; end + def at_beginning_of_season(arg=nil) + self.to_time.at_beginning_of_season(arg).to_date + end + def at_end_of_season(arg=nil) + self.to_time.at_end_of_season(arg).to_date + end + def within_season?(arg) + self.to_time.within_season?(arg) + end + module ClassMethods + def from_year_month_day(hash) + now = Time.now + Date.new((hash[:year] || now.year).to_i, (hash[:month] || now.month).to_i, (hash[:day] || now.day).to_i) + end + end + end + end +end diff --git a/lib/core_extensions/string/name.rb b/lib/core_extensions/string/name.rb new file mode 100644 index 000000000..974e76db1 --- /dev/null +++ b/lib/core_extensions/string/name.rb @@ -0,0 +1,64 @@ +module CoreExtensions + module String + module Name + def self.included(base) ; base.extend(ClassMethods) ; end + module ClassMethods + def random_string(len) + # generate a random string of alphanumerics, but to avoid user confusion, + # omit o/0 and 1/i/l + newpass = '' + chars = ("a".."z").to_a + ("A".."Z").to_a + ("2".."9").to_a - %w[O o L l I i] + 1.upto(len) { |i| newpass << chars[rand(chars.size-1)] } + return newpass + end + end + + # true if target is blank, or target when split on commas contains self, + # case-insensitively. used for checking promo codes and tags. + def contained_in_or_blank(target) + target.blank? || + target.upcase.split(/\s*,\s*/).include?(self.strip.upcase) + end + + def capitalize_each_word ; self.to_s.split.map(&:capitalize).join(' ') ; end + + def boldify(s, tag=:strong, tag_opts = {}) + tag_opts_str = tag_opts.each_pair { |k,v| "#{k}=\"#{v}\"" }.join " " + tagstart,tagend = "<#{tag.to_s} #{tag_opts_str}>", "" + self.gsub s, "#{tagstart}#{s}#{tagend}" + end + + def default_to(val) + self.blank? ? val : self.to_s + end + @@name_connectors = %w[and & van von der de di] + @@name_prefixes = /^m(a?c)(\w+)/i + def capitalize_name_word + # short all-caps (like "OJ") are left as-is + return self if self.match(/^[A-Z]+$/) + # words that are already BiCapitalized are left as-is + # (i.e., contain at least one uppercase letter that is preceded by + # a lowercase letter; catches McHugh, diBlasio, etc.) + return self if self.match( /[a-z][A-Z]/ ) + # single initial: capitalize the initial + return "#{self.upcase}." if self.match(/^\w$/i) + # connector word (von, van, de, etc.) - lowercase + return self.downcase if @@name_connectors.include?(self.downcase) + # default: capitalize first letter AND any letter after a hyphen + return self.gsub(/^(\w)|-(\w)/) { |a| a.upcase } + #self.match(@@name_prefixes) ? self.sub(@@name_prefixes, "M#{$1}#{$2.capitalize}") : + # self.capitalize + end + def name_capitalize + self.split(/[\., ]+/).map { |w| w.capitalize_name_word }.join(" ") + end + def first_and_last_from_full_name + names = self.split(/\s+/) + last = names.pop.to_s + last = "#{names.pop} #{last}" while @@name_connectors.include?(names.last) + first = names.join(' ') + return [first.strip,last.strip] + end + end + end +end diff --git a/lib/core_extensions/time/season.rb b/lib/core_extensions/time/season.rb new file mode 100644 index 000000000..2fb7904f6 --- /dev/null +++ b/lib/core_extensions/time/season.rb @@ -0,0 +1,77 @@ +module CoreExtensions + module Time + module Season + def self.included(base) + base.extend(ClassMethods) + end + + def at_end_of_day + (self + 1.day).midnight - 1.second + end + + def at_beginning_of_season(oldyear = nil) + startmon = Option.season_start_month + startday = Option.season_start_day + if (oldyear) + # year given: just return start of that season + Time.local(oldyear.to_i, startmon, startday) + else + startmon = 1 unless (1..12).include?(startmon) + startday = 1 unless (1..31).include?(startday) + newyr = (self.month > startmon || (self.month==startmon && self.mday >= startday)) ? self.year : (self.year - 1) + self.change(:month => startmon, :day => startday, :hour => 0, :year => newyr) + end + end + + def at_end_of_season(oldyear = nil) + if (oldyear) + # just return end of that season + self.at_beginning_of_season(oldyear) + 1.year - 1.second + else + self.at_beginning_of_season + 1.year - 1.second + end + end + + def this_season ; self.at_beginning_of_season.year ; end + + def within_season?(year) + year = year.year unless year.kind_of?(Numeric) + start = Time.local(year,Option.season_start_month, + Option.season_start_day).at_beginning_of_season + (start <= self) && (self <= start.at_end_of_season) + end + + module ClassMethods + # Needed since DB may not be in same timezone, so its notion of NOW() may + # not be correct + def at_beginning_of_season(arg=nil) ; ::Time.now.at_beginning_of_season(arg) ; end + def at_end_of_season(arg=nil) ; ::Time.now.at_end_of_season(arg) ; end + def this_season ; ::Time.now.this_season ; end + def db_now + "\"#{Time.now.to_formatted_s(:db)}\"" + end + def from_param(param,default=Time.now) + return default if param.blank? + return ::Time.parse(param) unless param.kind_of?(Hash) + t = ::Time.local(0,1,1,0,0,0) + [:year,:month,:day,:hour].each do |component| + t = t.change(component => param[component].to_i) if param.has_key?(component) + end + t = t.change(:min => param[:minute].to_i) if param.has_key?(:minute) + t = t.change(:sec => param[:second].to_i) if param.has_key?(:second) + t + end + + # Extract two dates from jquery-ui-datepicker formatted params field + def range_from_params(json) + return Time.now,Time.now if json.empty? + obj = JSON(json) + min = Time.parse(obj['start'].to_s).at_beginning_of_day + max = Time.parse(obj['end'].to_s).at_end_of_day + min,max = max,min if min > max + return min, max + end + end + end + end +end diff --git a/lib/date_time_extras.rb b/lib/date_time_extras.rb deleted file mode 100644 index 8135e6fdb..000000000 --- a/lib/date_time_extras.rb +++ /dev/null @@ -1,99 +0,0 @@ -# new contructor for making a Time from menus - -# add a couple of useful formats to ActiveSupport to_formatted_s conversion -ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!({ - :compact => "%m/%d/%y", - :filename => "%Y-%m-%d", - :date_only => "%e %B %Y", - :showtime => '%A, %b %-e, %-l:%M %p', - :showtime_including_year => '%A, %b %-e, %Y, %-l:%M %p', - :month_day_only => "%b %-e", - :month_day_year => "%b %-e, %Y" -}) - -class Time - # Needed since DB may not be in same timezone, so its notion of NOW() may - # not be correct - def self.db_now - "\"#{Time.now.to_formatted_s(:db)}\"" - end - - def at_end_of_day - (self + 1.day).midnight - 1.second - end - - def at_beginning_of_season(oldyear = nil) - startmon = Option.season_start_month - startday = Option.season_start_day - if (oldyear) - # year given: just return start of that season - Time.local(oldyear.to_i, startmon, startday) - else - startmon = 1 unless (1..12).include?(startmon) - startday = 1 unless (1..31).include?(startday) - newyr = (self.month > startmon || (self.month==startmon && self.mday >= startday)) ? self.year : (self.year - 1) - self.change(:month => startmon, :day => startday, :hour => 0, :year => newyr) - end - end - - def at_end_of_season(oldyear = nil) - if (oldyear) - # just return end of that season - self.at_beginning_of_season(oldyear) + 1.year - 1.second - else - self.at_beginning_of_season + 1.year - 1.second - end - end - - def this_season ; self.at_beginning_of_season.year ; end - - def self.at_beginning_of_season(arg=nil) ; Time.now.at_beginning_of_season(arg) ; end - def self.at_end_of_season(arg=nil) ; Time.now.at_end_of_season(arg) ; end - def self.this_season ; Time.now.this_season ; end - - def within_season?(year) - year = year.year unless year.kind_of?(Numeric) - start = Time.local(year,Option.season_start_month, - Option.season_start_day).at_beginning_of_season - (start <= self) && (self <= start.at_end_of_season) - end - - def self.from_param(param,default=Time.now) - return default if param.blank? - return Time.parse(param) unless param.kind_of?(Hash) - t = Time.local(0,1,1,0,0,0) - [:year,:month,:day,:hour].each do |component| - t = t.change(component => param[component].to_i) if param.has_key?(component) - end - t = t.change(:min => param[:minute].to_i) if param.has_key?(:minute) - t = t.change(:sec => param[:second].to_i) if param.has_key?(:second) - t - end - - # Extract two dates from jquery-ui-datepicker formatted params field - def self.range_from_params(json) - return Time.now,Time.now if json.empty? - obj = JSON(json) - min = Time.parse(obj['start'].to_s).at_beginning_of_day - max = Time.parse(obj['end'].to_s).at_end_of_day - min,max = max,min if min > max - return min, max - end - -end - -class Date - def Date.from_year_month_day(hash) - now = Time.now - Date.new((hash[:year] || now.year).to_i, (hash[:month] || now.month).to_i, (hash[:day] || now.day).to_i) - end - def at_beginning_of_season(arg=nil) - self.to_time.at_beginning_of_season(arg).to_date - end - def at_end_of_season(arg=nil) - self.to_time.at_end_of_season(arg).to_date - end - def within_season?(arg) - self.to_time.within_season?(arg) - end -end diff --git a/lib/string_extras.rb b/lib/string_extras.rb deleted file mode 100644 index 0a452684d..000000000 --- a/lib/string_extras.rb +++ /dev/null @@ -1,73 +0,0 @@ -# makes it easier to check for empty arrays when submitted from forms -class NilClass - def empty? ; true ; end -end - -class String - - def self.random_string(len) - # generate a random string of alphanumerics, but to avoid user confusion, - # omit o/0 and 1/i/l - newpass = '' - chars = ("a".."z").to_a + ("A".."Z").to_a + ("2".."9").to_a - %w[O o L l I i] - 1.upto(len) { |i| newpass << chars[rand(chars.size-1)] } - return newpass - end - - # true if target is blank, or target when split on commas contains self, - # case-insensitively. used for checking promo codes and tags. - def contained_in_or_blank(target) - target.blank? || - target.upcase.split(/\s*,\s*/).include?(self.strip.upcase) - end - - def capitalize_each_word ; self.to_s.split.map(&:capitalize).join(' ') ; end - - def boldify(s, tag=:strong, tag_opts = {}) - tag_opts_str = tag_opts.each_pair { |k,v| "#{k}=\"#{v}\"" }.join " " - tagstart,tagend = "<#{tag.to_s} #{tag_opts_str}>", "" - self.gsub s, "#{tagstart}#{s}#{tagend}" - end - - def default_to(val) - self.blank? ? val : self.to_s - end - @@name_connectors = %w[and & van von der de di] - @@name_prefixes = /^m(a?c)(\w+)/i - def capitalize_name_word - # short all-caps (like "OJ") are left as-is - return self if self.match(/^[A-Z]+$/) - # words that are already BiCapitalized are left as-is - # (i.e., contain at least one uppercase letter that is preceded by - # a lowercase letter; catches McHugh, diBlasio, etc.) - return self if self.match( /[a-z][A-Z]/ ) - # single initial: capitalize the initial - return "#{self.upcase}." if self.match(/^\w$/i) - # connector word (von, van, de, etc.) - lowercase - return self.downcase if @@name_connectors.include?(self.downcase) - # default: capitalize first letter AND any letter after a hyphen - return self.gsub(/^(\w)|-(\w)/) { |a| a.upcase } - #self.match(@@name_prefixes) ? self.sub(@@name_prefixes, "M#{$1}#{$2.capitalize}") : - # self.capitalize - end - def name_capitalize - self.split(/[\., ]+/).map { |w| w.capitalize_name_word }.join(" ") - end - def first_and_last_from_full_name - names = self.split(/\s+/) - last = names.pop.to_s - last = "#{names.pop} #{last}" while @@name_connectors.include?(names.last) - first = names.join(' ') - return [first.strip,last.strip] - end -end - -# for safety, extend Object and NilClass etc with the capitalization helpers - -class Object - def name_capitalize ; self.nil? ? "" : self.to_s ; end -end - -class NilClass #:nodoc: - def name_capitalize ; '' ; end -end