├── README ├── Rakefile ├── generators └── deploy_configs │ ├── deploy_configs_generator.rb │ └── templates │ ├── httpd.conf │ └── logrotate ├── init.rb ├── install.rb ├── lib ├── awesomeness.rb └── awesomeness │ ├── core_ext │ ├── array.rb │ ├── enumerable.rb │ ├── float.rb │ ├── hash.rb │ ├── object.rb │ ├── range.rb │ └── string.rb │ ├── text_helper.rb │ └── trailing_slash.rb ├── recipes ├── awesomeness.rb └── awesomeness │ ├── apache.rb │ ├── assets.rb │ ├── ferret.rb │ ├── logs.rb │ └── mongrel.rb ├── tasks └── awesomeness.rake └── test ├── core_ext ├── array_test.rb └── enumerable_test.rb ├── test_helper.rb ├── text_helper_test.rb └── trailing_slash_test.rb /README: -------------------------------------------------------------------------------- 1 | Collective Idea's Awesomeness 2 | ============================= 3 | 4 | A collection of stuff that we use often, but not generic enough to go in another plugin. 5 | 6 | If you've stumbled across this and love/hate it, let us know! 7 | 8 | == Compatability 9 | 10 | This plugin is compatible with edge-rails that is slated to be Rails 2.2. For a version compatible with 2.1, check out the "rails-2.1" tag from git. 11 | 12 | == Core Extensions 13 | 14 | * Object#tap (http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-expressions) 15 | 16 | * String#widont to make typography nicer (http://shauninman.com/archive/2006/08/22/widont_wordpress_plugin) 17 | 18 | * Array#uniq with a block 19 | 20 | >> %w(the cow jumped over the moon).uniq {|s| s.length } 21 | => ["the", "jumped", "over"] 22 | 23 | * Round floats to the nearest x 24 | 25 | >> 5.38475.round(0.5) 26 | => 5.5 27 | 28 | * Hash goodies 29 | 30 | >> {:a => [1,3,4], :b => [2,5]}.without(:a => 1) 31 | => {:a => [3,4], :b => [2,5]} 32 | 33 | >> {:a => "", :b => nil, :c => 1}.compact 34 | => {:c => 1} 35 | 36 | * And more… 37 | 38 | == Rails Helpers 39 | 40 | * Unicode TextHelper additions that change the default truncate & excerpt string to an elipsis (…) instead of just three periods (...) 41 | 42 | * Add widont to textilize methods 43 | 44 | * Transparent removal of trailing slashes in URLs 45 | 46 | == Rake Tasks 47 | 48 | == Capistrano Recipes 49 | 50 | * Use :remote_cache by default 51 | 52 | * Disable and enable web during restarts 53 | 54 | * Run deploy:cleanup after deploys 55 | 56 | * Backups -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | require 'rake/testtask' 3 | require 'rake/rdoctask' 4 | 5 | desc 'Default: run unit tests.' 6 | task :default => :test 7 | 8 | desc 'Test the awesomeness plugin.' 9 | Rake::TestTask.new(:test) do |t| 10 | t.libs << 'lib' 11 | t.pattern = 'test/**/*_test.rb' 12 | t.verbose = true 13 | end 14 | 15 | desc 'Generate documentation for the awesomeness plugin.' 16 | Rake::RDocTask.new(:rdoc) do |rdoc| 17 | rdoc.rdoc_dir = 'rdoc' 18 | rdoc.title = 'Awesomeness' 19 | rdoc.options << '--line-numbers' << '--inline-source' 20 | rdoc.rdoc_files.include('README') 21 | rdoc.rdoc_files.include('lib/**/*.rb') 22 | end -------------------------------------------------------------------------------- /generators/deploy_configs/deploy_configs_generator.rb: -------------------------------------------------------------------------------- 1 | require 'capistrano' 2 | require 'capistrano/cli' 3 | 4 | # TODO: error handling. Check if Cap config doesn't exist 5 | class DeployConfigsGenerator < Rails::Generator::Base 6 | default_options :ports => "8000,8001,8002" 7 | attr_reader :config 8 | 9 | def initialize(runtime_args, runtime_options = {}) 10 | super 11 | options[:ports] = options[:ports].split(',') 12 | assign_capistrano_config! 13 | end 14 | 15 | def manifest 16 | record do |m| 17 | m.directory "config" 18 | m.template "logrotate", File.join("config", "logrotate") 19 | m.template "httpd.conf", File.join("config", "httpd.conf") 20 | end 21 | end 22 | 23 | private 24 | 25 | def assign_capistrano_config! 26 | @config = Capistrano::Configuration.new 27 | @config.load Capistrano::CLI::DEFAULT_RECIPES.select {|file| File.exist?(File.join(RAILS_ROOT, file)) } 28 | end 29 | 30 | def add_options!(opt) 31 | opt.separator '' 32 | opt.separator 'Options:' 33 | opt.on("--ports ports", "Ports to run mongrel on") do |v| 34 | options[:ports] = v 35 | end 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /generators/deploy_configs/templates/httpd.conf: -------------------------------------------------------------------------------- 1 | > 2 | <% options[:ports].each do |port| -%> 3 | BalancerMember http://127.0.0.1:<%= port %> 4 | <% end -%> 5 | 6 | 7 | RewriteEngine On 8 | 9 | # Uncomment for rewrite debugging 10 | #RewriteLog logs/your_app_rewrite_log 11 | #RewriteLogLevel 9 12 | 13 | # Check for maintenance file and redirect all requests 14 | RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f 15 | RewriteCond %{SCRIPT_FILENAME} !maintenance.html 16 | RewriteRule ^.*$ /system/maintenance.html [L] 17 | 18 | # Rewrite index to check for static 19 | RewriteRule ^/$ /index.html [QSA] 20 | 21 | # Rewrite to check for Rails cached page 22 | RewriteRule ^([^.]+)$ $1.html [QSA] 23 | 24 | # Redirect all non-static requests to cluster 25 | RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f 26 | RewriteRule ^/(.*)$ balancer://<%= config.application %>%{REQUEST_URI} [P,QSA,L] 27 | 28 | # Deflate 29 | AddOutputFilterByType DEFLATE text/html text/plain text/xml 30 | BrowserMatch ^Mozilla/4 gzip-only-text/html 31 | BrowserMatch ^Mozilla/4\.0[678] no-gzip 32 | BrowserMatch \bMSIE !no-gzip !gzip-only-text/html 33 | 34 | # Uncomment for deflate debugging 35 | #DeflateFilterNote Input input_info 36 | #DeflateFilterNote Output output_info 37 | #DeflateFilterNote Ratio ratio_info 38 | #LogFormat '"%r" %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate 39 | #CustomLog logs/your_app_deflate_log deflate 40 | 41 | #ErrorLog logs/your_app_error_log 42 | #CustomLog logs/your_access_log combined -------------------------------------------------------------------------------- /generators/deploy_configs/templates/logrotate: -------------------------------------------------------------------------------- 1 | <%= config.shared_path %>/log/*log { 2 | daily 3 | rotate 7 4 | compress 5 | missingok 6 | notifempty 7 | sharedscripts 8 | postrotate 9 | for i in `ls <%= config.shared_path %>/log/*.pid`; do 10 | kill -USR2 `cat $i` 11 | done 12 | endscript 13 | } -------------------------------------------------------------------------------- /init.rb: -------------------------------------------------------------------------------- 1 | require 'awesomeness' 2 | -------------------------------------------------------------------------------- /install.rb: -------------------------------------------------------------------------------- 1 | puts IO.read(File.join(File.dirname(__FILE__), 'README')) 2 | -------------------------------------------------------------------------------- /lib/awesomeness.rb: -------------------------------------------------------------------------------- 1 | Dir[File.dirname(__FILE__) + "/awesomeness/**/*.rb"].each {|f| require f } 2 | 3 | # From: http://weblog.jamisbuck.org/2007/1/31/more-on-watching-activerecord 4 | # Easy way to view logs in script/console. 5 | # simply type: log_to(STDOUT) 6 | # and all of your active record queries will show up inline. 7 | def log_to(stream = STDOUT) 8 | ActiveRecord::Base.logger = Logger.new(stream) 9 | ActiveRecord::Base.clear_active_connections! 10 | end -------------------------------------------------------------------------------- /lib/awesomeness/core_ext/array.rb: -------------------------------------------------------------------------------- 1 | class Array 2 | 3 | def randomize(limit = length) 4 | choices = dup 5 | returning([]) do |result| 6 | [limit, length].min.times do 7 | result << choices.delete_at(Kernel.rand(choices.length)) 8 | end 9 | end.compact 10 | end 11 | 12 | def uniq_with_block!(&block) 13 | uniq_without_block! 14 | if block_given? 15 | grouped = group_by(&block) 16 | grouped.each do |key,duplicates| 17 | delete_at(index(duplicates.pop)) while duplicates.size > 1 18 | end 19 | end 20 | self 21 | end 22 | alias_method_chain :uniq!, :block 23 | 24 | def uniq_with_block(&block) 25 | dup.uniq!(&block) 26 | end 27 | alias_method_chain :uniq, :block 28 | 29 | def pad(pad_to_length, padding = nil) 30 | dup.pad! pad_to_length, padding 31 | end 32 | 33 | def pad!(pad_to_length, padding = nil) 34 | self << padding while pad_to_length > length 35 | self 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /lib/awesomeness/core_ext/enumerable.rb: -------------------------------------------------------------------------------- 1 | module Enumerable 2 | 3 | # Divide into groups 4 | def chunk(number_of_chunks, padding = false) 5 | chunk_size = (size.to_f / number_of_chunks).ceil 6 | chunk_size = 1 if chunk_size < 1 7 | returning enum_for(:each_slice, chunk_size).to_a do |result| 8 | result << [] while result.length < number_of_chunks 9 | result.last.pad!(result.first.length, padding) unless padding == false 10 | end 11 | end 12 | alias / chunk 13 | 14 | end -------------------------------------------------------------------------------- /lib/awesomeness/core_ext/float.rb: -------------------------------------------------------------------------------- 1 | class Float 2 | def round(round_to = 1.0) 3 | mod = self % round_to 4 | rounded = self - mod + (mod >= round_to/2.0 ? round_to : 0) 5 | rounded % 1 == 0 ? rounded.to_i : rounded 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/awesomeness/core_ext/hash.rb: -------------------------------------------------------------------------------- 1 | class Hash 2 | # Usage {:a => [1,3,4], :b => [2,5]}.without(:a => 1) 3 | # returns {:a => [3,4], :b => [2,5]} 4 | def without(hash) 5 | hash = hash.with_indifferent_access if self.instance_of?(HashWithIndifferentAccess) 6 | # create a new hash using this class, so we get a new HashWithIndifferentAccess if this is one 7 | inject(self.class.new) do |result,(k,v)| 8 | result[k] = (hash[k] && v.respond_to?(:reject) ? v.reject {|v,_| v == hash[k] } : v) 9 | result 10 | end 11 | end 12 | 13 | def compact! 14 | delete_if { |k,v| v.blank? } 15 | end 16 | 17 | def compact 18 | dup.compact! 19 | end 20 | end -------------------------------------------------------------------------------- /lib/awesomeness/core_ext/object.rb: -------------------------------------------------------------------------------- 1 | class Object 2 | # See http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-expressions 3 | # Will be added in Ruby 1.9 4 | def tap 5 | yield self 6 | self 7 | end if RUBY_VERSION < '1.9' 8 | end -------------------------------------------------------------------------------- /lib/awesomeness/core_ext/range.rb: -------------------------------------------------------------------------------- 1 | class Range 2 | 3 | def include_with_range?(value) 4 | if value.is_a?(Range) 5 | self.first <= value.first && 6 | (self.exclude_end? && !value.exclude_end? ? 7 | self.last > value.last : 8 | self.last >= value.last) 9 | else 10 | include_without_range?(value) 11 | end 12 | end unless defined?(ActiveSupport::CoreExtensions::Range::IncludeRange) 13 | alias_method_chain(:include?, :range) unless defined?(ActiveSupport::CoreExtensions::Range::IncludeRange) 14 | 15 | def overlap?(range) 16 | self.include?(range.first) || 17 | self.include?(range.exclude_end? ? range.last - 1 : range.last) 18 | end 19 | 20 | alias_method :original_step, :step 21 | def step(value = 1, &block) 22 | if block_given? 23 | original_step(value, &block) 24 | else 25 | returning [] do |array| 26 | original_step(value) {|step| array << step } 27 | end 28 | end 29 | end 30 | 31 | end -------------------------------------------------------------------------------- /lib/awesomeness/core_ext/string.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | class String 3 | # Widon't 4 | # Based on the original by Shaun Inman: http://shauninman.com/archive/2006/08/22/widont_wordpress_plugin 5 | # And the Ruby versions here: http://mucur.name/posts/widon-t-helper-for-rails-2 6 | # This version replaces   with a unicode non-breaking space (option-space on a Mac) 7 | def widont 8 | self.gsub(/([^\s])\s+([^\s]+)(\s*)$/, '\1 \2\3') 9 | end 10 | 11 | def mb_chars 12 | chars 13 | end unless ''.respond_to?(:mb_chars) 14 | end -------------------------------------------------------------------------------- /lib/awesomeness/text_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | module ActionView 3 | module Helpers 4 | module TextHelper 5 | # Awesome truncate 6 | # First regex truncates to the length, plus the rest of that word, if any. 7 | # Second regex removes any trailing whitespace or punctuation (except ;). 8 | # Unlike the regular truncate method, this avoids the problem with cutting 9 | # in the middle of an entity ex.: truncate("this & that",9) => "this &am..." 10 | # though it will not be the exact length. 11 | def awesome_truncate(text, length = 30, truncate_string = "…") 12 | return if text.nil? 13 | l = length - truncate_string.mb_chars.length 14 | text.mb_chars.length > length ? text[/\A.{#{l}}\w*\;?/m][/.*[\w\;]/m] + truncate_string : text 15 | end 16 | 17 | def truncate_with_title(text, length = 30, truncate_string = "…") 18 | if text.mb_chars.length > length 19 | content_tag :span, truncate(text), :title => text 20 | else 21 | text 22 | end 23 | end 24 | 25 | # Better versions of standard truncate and excerpt 26 | def truncate_with_better_default(text, options) 27 | options = {:length => 30, :truncate_string => "…"}.merge(options) 28 | truncate_without_better_default(text, options) 29 | end 30 | alias_method_chain :truncate, :better_default 31 | 32 | def excerpt_with_better_default(text, phrase, options) 33 | options = {radius => 100, excerpt_string => "…"}.merge(options) 34 | excerpt_without_better_default(text, phrase, options) 35 | end 36 | alias_method_chain :excerpt, :better_default 37 | 38 | # Widon't 39 | # We use this method instead of String#widont directly because textilize is often called with nil. 40 | # This duplicates textilize's solution of returning the empty string if blank. 41 | def widont(text) 42 | text.blank? ? '' : text.widont 43 | end 44 | 45 | def textilize_with_widont(text) 46 | textilize_without_widont widont(text) 47 | end 48 | alias_method_chain :textilize, :widont 49 | 50 | def textilize_without_paragraph_with_widont(text) 51 | textilize_without_paragraph_without_widont widont(text) 52 | end 53 | alias_method_chain :textilize_without_paragraph, :widont 54 | 55 | # Inserts a unicode non-breaking space character ' ' 56 | # since   shouldn't be used in proper XHTML 57 | def nbsp 58 | ' ' 59 | end 60 | end 61 | end 62 | end -------------------------------------------------------------------------------- /lib/awesomeness/trailing_slash.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # Disambiguate URLs by removing trailing slashes 3 | # Idea from http://fleetingideas.com/post/6539239 4 | # This version works with query strings. 5 | module CollectiveIdea #:nodoc: 6 | module ActionController 7 | module TrailingSlash #:nodoc: 8 | def self.included(base) #:nodoc: 9 | base.before_filter :remove_trailing_slash 10 | base.send :include, InstanceMethods 11 | end 12 | 13 | module InstanceMethods 14 | private 15 | def remove_trailing_slash 16 | request_uri = remove_trailing_slash_from(request.request_uri) 17 | if request.request_uri.length > 1 && request.request_uri != request_uri 18 | headers['Status'] = '301 Moved Permanently' 19 | redirect_to request.protocol + request.host_with_port + request_uri and return false 20 | end 21 | end 22 | 23 | def remove_trailing_slash_from(uri) 24 | uri.split('?').each{|s| s.sub!(/\/$/, '')}.join('?').sub!(/\A^\/?/, '/\1') 25 | #uri.sub(/\/(^\?*)?(\?.+)?\/?$/, '/\1\2')#.sub(/\/+/, '/') 26 | end 27 | end 28 | end 29 | end 30 | end 31 | 32 | ActionController::Base.send :include, CollectiveIdea::ActionController::TrailingSlash 33 | -------------------------------------------------------------------------------- /recipes/awesomeness.rb: -------------------------------------------------------------------------------- 1 | # load 'awesomeness' 2 | # 3 | # A collection of commonly-used (yet, non-intrusive) Capistrano tasks at Collective Idea. 4 | # 5 | 6 | load_paths.unshift File.expand_path(File.dirname(__FILE__)) 7 | 8 | # don't do a fresh checkout, just svn update 9 | set :deploy_via, :remote_cache 10 | 11 | after "deploy:update_code", "deploy:web:disable" 12 | before "deploy:stop", "deploy:web:disable" 13 | before "deploy:restart", "deploy:web:disable" 14 | after "deploy:restart", "deploy:web:enable" 15 | after "deploy:start", "deploy:web:enable" 16 | 17 | after "deploy", "deploy:cleanup" 18 | after "deploy:migrations", "deploy:cleanup" 19 | -------------------------------------------------------------------------------- /recipes/awesomeness/apache.rb: -------------------------------------------------------------------------------- 1 | namespace :deploy do 2 | namespace :apache do 3 | desc "Start Apache" 4 | task :start, :roles => :web do 5 | sudo "/etc/init.d/httpd start > /dev/null" 6 | end 7 | 8 | desc "Stop Apache" 9 | task :stop, :roles => :web do 10 | sudo "/etc/init.d/httpd stop > /dev/null" 11 | end 12 | 13 | desc "Restart Apache" 14 | task :restart, :roles => :web do 15 | sudo "/etc/init.d/httpd restart > /dev/null" 16 | end 17 | 18 | desc "Reload Apache" 19 | task :reload, :roles => :web do 20 | sudo "/etc/init.d/httpd reload > /dev/null" 21 | end 22 | end 23 | end -------------------------------------------------------------------------------- /recipes/awesomeness/assets.rb: -------------------------------------------------------------------------------- 1 | _cset(:assets) { abort "Please specify assets, set :assets, %w(foo bar)" } 2 | 3 | after "deploy:setup", "assets:setup" 4 | after "deploy:update_code", "assets:symlink" 5 | 6 | namespace :assets do 7 | def asset_dirs 8 | fetch(:assets).map {|dir| File.join(shared_path, 'assets', dir) } 9 | end 10 | 11 | task :setup, :role => :app do 12 | run "umask 02 && mkdir -p #{asset_dirs.join(' ')}" 13 | end 14 | 15 | task :symlink, :role => :app do 16 | setup 17 | fetch(:assets).each do |asset| 18 | run "rm -f #{release_path}/public/#{asset}" 19 | run "ln -s #{shared_path}/assets/#{asset} #{release_path}/public/#{asset}" 20 | end 21 | end 22 | 23 | # FIXME: this is brittle 24 | task :backup, :role => :app do 25 | backup_dir = File.expand_path(File.dirname(__FILE__) + '/../../../../public/') 26 | puts "backing up remote assets to #{backup_dir}" 27 | puts `rsync -e ssh -qr --delete #{user}@#{roles[:app][0].host}:#{shared_path}/assets/* #{backup_dir}` 28 | end 29 | 30 | end -------------------------------------------------------------------------------- /recipes/awesomeness/ferret.rb: -------------------------------------------------------------------------------- 1 | 2 | before 'deploy:start', 'deploy:ferret:start' 3 | before 'deploy:stop', 'deploy:ferret:stop' 4 | before 'deploy:restart', 'deploy:ferret:restart' 5 | namespace :deploy do 6 | namespace :ferret do 7 | desc "Start the ferret server" 8 | task :start do 9 | run "cd #{current_path}; script/ferret_server -e #{fetch(:rails_env, 'production')} start" 10 | end 11 | 12 | desc "Stop the ferret server" 13 | task :stop do 14 | run "cd #{current_path}; script/ferret_server -e #{fetch(:rails_env, 'production')} stop" 15 | end 16 | 17 | desc "Restart the ferret server" 18 | task :restart do 19 | stop 20 | start 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /recipes/awesomeness/logs.rb: -------------------------------------------------------------------------------- 1 | namespace :logs do 2 | desc "tail production log files" 3 | task :tail, :roles => :app do 4 | run "tail -f #{shared_path}/log/production.log" do |channel, stream, data| 5 | puts # for an extra line break before the host name 6 | puts "#{channel[:host]}: #{data}" 7 | break if stream == :err 8 | end 9 | end 10 | 11 | desc "Backup the remote production log" 12 | task :backup, :roles => :app do 13 | dir = File.expand_path(File.dirname(__FILE__) + '/../../../../backups') 14 | filename = "#{application}.#{Time.now.to_i}.production.log" 15 | `mkdir -p #{dir}` 16 | get "#{shared_path}/log/production.log", "#{dir}/#{filename}" 17 | end 18 | 19 | 20 | desc "check production log files in textmate(tm)" 21 | task :mate, :roles => :app do 22 | require 'tempfile' 23 | tmp = Tempfile.open('w') 24 | logs = Hash.new { |h,k| h[k] = '' } 25 | 26 | run "tail -n500 #{shared_path}/log/production.log" do |channel, stream, data| 27 | logs[channel[:host]] << data 28 | break if stream == :err 29 | end 30 | 31 | logs.each do |host, log| 32 | tmp.write("--- #{host} ---\n\n") 33 | tmp.write(log + "\n") 34 | end 35 | 36 | exec "mate -w #{tmp.path}" 37 | tmp.close 38 | end 39 | end -------------------------------------------------------------------------------- /recipes/awesomeness/mongrel.rb: -------------------------------------------------------------------------------- 1 | # Deprecated. The functionality is now in mongrel_cluster for Cap 2 2 | require 'mongrel_cluster/recipes' -------------------------------------------------------------------------------- /tasks/awesomeness.rake: -------------------------------------------------------------------------------- 1 | desc "Run migrations and prepare the test database" 2 | task :db => ['db:migrate', 'db:test:prepare'] -------------------------------------------------------------------------------- /test/core_ext/array_test.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../test_helper' 2 | require 'awesomeness/core_ext/array' 3 | 4 | class ArrayTest < Test::Unit::TestCase 5 | 6 | def test_pad 7 | a = [1,2,3] 8 | assert_equal [1,2,3,nil,nil], a.pad(5) 9 | end 10 | 11 | def test_pad_does_not_exceed_length 12 | a = [1,2,3] 13 | assert_equal a, a.pad(2) 14 | assert_equal a, a.pad(3) 15 | end 16 | 17 | def test_pad_with_custom_padding 18 | a = [1,2,3] 19 | assert_equal [1,2,3,'foo'], a.pad(4, 'foo') 20 | end 21 | 22 | def test_pad_does_not_modify_original 23 | a = [1,2,3] 24 | a.pad(4) 25 | assert_equal 3, a.length 26 | end 27 | 28 | def test_pad_does_not_modify_original 29 | a = [1,2,3] 30 | a.pad(4) 31 | assert_equal 3, a.length 32 | end 33 | 34 | def test_pad! 35 | a = [1,2,3] 36 | a.pad!(4, 'x') 37 | assert_equal [1,2,3,'x'], a 38 | end 39 | 40 | def test_randomize_length 41 | assert_equal 4, (1..10).to_a.randomize(4).length 42 | end 43 | 44 | def test_randomize_with_fewer_options 45 | a = [1,2,3] 46 | assert_equal 3, a.randomize(10).length 47 | end 48 | end -------------------------------------------------------------------------------- /test/core_ext/enumerable_test.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../test_helper' 2 | require 'awesomeness/core_ext/array' 3 | require 'awesomeness/core_ext/enumerable' 4 | 5 | class EnumerableTest < Test::Unit::TestCase 6 | 7 | def test_chunk_evenly 8 | assert_equal [[1], [2], [3]], [1, 2, 3].chunk(3) 9 | end 10 | 11 | def test_divide_evenly 12 | assert_equal [[1], [2], [3]], [1, 2, 3] / 3 13 | assert_equal [[1, 2], [3, 4], [5, 6]], [1, 2, 3, 4, 5, 6].chunk(3) 14 | assert_equal [[1,2,3,4,5],[6,7,8,9,10]], ((1..10).to_a / 2) 15 | end 16 | 17 | def test_chunk_unevenly 18 | assert_equal [[1, 2], [3]], [1, 2, 3].chunk(2) 19 | assert_equal [[1,2,3,4,5,6,7],[8,9,10,11,12,13]], ((1..13).to_a / 2) 20 | assert_equal [[1,2,3,4],[5,6,7,8],[9,10]], ((1..10).to_a / 3) 21 | end 22 | 23 | def test_chunk_fills_with_empty_arrays 24 | assert_equal [[1], [], []], [1].chunk(3) 25 | end 26 | 27 | def test_chunking_does_not_modify_original 28 | array = [1, 2, 3] 29 | assert_equal 3, array.length 30 | assert_equal [[1], [2], [3]], array.chunk(3) 31 | assert_equal 3, array.length 32 | end 33 | 34 | def test_chunk_unevenly_with_padding 35 | assert_equal [[1, 2], [3, nil]], [1, 2, 3].chunk(2, nil) 36 | assert_equal [[1,2,3,4,5,6,7],[8,9,10,11,12,13, 'foo']], ((1..13).to_a.chunk(2, 'foo')) 37 | end 38 | 39 | def test_divide_by_zero 40 | assert_equal [[],[]], [].chunk(2) 41 | end 42 | 43 | end -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | $: << File.expand_path(File.dirname(__FILE__) + '/../lib') 2 | 3 | require 'rubygems' 4 | require 'test/unit' 5 | require 'active_support' -------------------------------------------------------------------------------- /test/text_helper_test.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | require 'rubygems' 3 | require 'action_view' 4 | require File.join(File.dirname(__FILE__), '..', 'lib', 'awesomeness', 'text_helper') 5 | 6 | 7 | class TextHelperTest < Test::Unit::TestCase 8 | include ActionView::Helpers::TextHelper 9 | 10 | def test_awesome_truncate_with_nil 11 | assert_nil awesome_truncate(nil) 12 | end 13 | 14 | def test_awesome_truncate_with_blank 15 | assert_equal '', awesome_truncate('') 16 | end 17 | 18 | def test_awesome_truncate 19 | assert_equal 'foo...', awesome_truncate('foo bar baz', 5, '...') 20 | end 21 | 22 | def test_awesome_truncate_with_sentence 23 | assert_equal 'foo bar...', awesome_truncate('foo bar. baz', 8, '...') 24 | end 25 | 26 | # TODO: this would be sweet 27 | # def test_awesome_truncate_with_html 28 | # assert_equal 'foo...', awesome_truncate('foo ', 8, '...') 29 | # end 30 | end -------------------------------------------------------------------------------- /test/trailing_slash_test.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | module ActionController 3 | class AbstractRequest 4 | end 5 | end 6 | require File.join(File.dirname(__FILE__), '..', 'lib', 'awesomeness', 'trailing_slash') 7 | 8 | 9 | class TrailingSlashTest < Test::Unit::TestCase 10 | include CollectiveIdea::ActionController::TrailingSlash::InstanceMethods 11 | 12 | def test_remove_without_querystring_1 13 | assert_equal '/foo', remove_trailing_slash_from('/foo/') 14 | end 15 | def test_remove_without_querystring_2 16 | assert_equal '/foo/bar', remove_trailing_slash_from('/foo/bar/') 17 | end 18 | def test_remove_without_querystring_3 19 | assert_equal '/foo/bar/baz', remove_trailing_slash_from('/foo/bar/baz/') 20 | end 21 | def test_remove_without_querystring_4 22 | assert_equal '/foo/bar/baz.html', remove_trailing_slash_from('/foo/bar/baz.html/') 23 | end 24 | 25 | def test_no_remove_needed_without_querystring_1 26 | assert_equal '/foo', remove_trailing_slash_from('/foo') 27 | end 28 | def test_no_remove_needed_without_querystring_2 29 | assert_equal '/foo/bar', remove_trailing_slash_from('/foo/bar') 30 | end 31 | def test_no_remove_needed_without_querystring_3 32 | assert_equal '/foo/bar/baz', remove_trailing_slash_from('/foo/bar/baz') 33 | end 34 | def test_no_remove_needed_without_querystring_4 35 | assert_equal '/foo/bar/baz.html', remove_trailing_slash_from('/foo/bar/baz.html') 36 | end 37 | 38 | def test_remove_with_querystring_1 39 | assert_equal '/foo?bar=baz', remove_trailing_slash_from('/foo/?bar=baz') 40 | end 41 | def test_remove_with_querystring_2 42 | assert_equal '/foo/foo?bar=baz', remove_trailing_slash_from('/foo/foo/?bar=baz') 43 | end 44 | def test_remove_with_querystring_3 45 | assert_equal '/foo/foo?bar=baz', remove_trailing_slash_from('/foo/foo/?bar=baz/') 46 | end 47 | 48 | def test_no_remove_needed_with_querystring_1 49 | assert_equal '/foo?bar=baz', remove_trailing_slash_from('/foo?bar=baz') 50 | end 51 | def test_no_remove_needed_with_querystring_2 52 | assert_equal '/foo/foo?bar=baz', remove_trailing_slash_from('/foo/foo?bar=baz') 53 | end 54 | 55 | def test_no_remove_needed_with_querystring_without_path 56 | assert_equal '/?bar=baz', remove_trailing_slash_from('/?bar=baz') 57 | end 58 | 59 | def test_slash_only 60 | assert_equal '/', remove_trailing_slash_from('/') 61 | end 62 | 63 | def test_double_slash 64 | assert_equal '/', remove_trailing_slash_from('//') 65 | end 66 | end 67 | --------------------------------------------------------------------------------