friendly_id_globalize3 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/Changelog.md +354 -0
  2. data/Contributors.md +43 -0
  3. data/Guide.md +686 -0
  4. data/MIT-LICENSE +19 -0
  5. data/README.md +99 -0
  6. data/Rakefile +75 -0
  7. data/extras/README.txt +3 -0
  8. data/extras/bench.rb +40 -0
  9. data/extras/extras.rb +38 -0
  10. data/extras/prof.rb +19 -0
  11. data/extras/template-gem.rb +26 -0
  12. data/extras/template-plugin.rb +28 -0
  13. data/generators/friendly_id/friendly_id_generator.rb +30 -0
  14. data/generators/friendly_id/templates/create_slugs.rb +18 -0
  15. data/lib/friendly_id.rb +93 -0
  16. data/lib/friendly_id/active_record.rb +74 -0
  17. data/lib/friendly_id/active_record_adapter/configuration.rb +68 -0
  18. data/lib/friendly_id/active_record_adapter/finders.rb +148 -0
  19. data/lib/friendly_id/active_record_adapter/relation.rb +165 -0
  20. data/lib/friendly_id/active_record_adapter/simple_model.rb +63 -0
  21. data/lib/friendly_id/active_record_adapter/slug.rb +77 -0
  22. data/lib/friendly_id/active_record_adapter/slugged_model.rb +122 -0
  23. data/lib/friendly_id/active_record_adapter/tasks.rb +72 -0
  24. data/lib/friendly_id/configuration.rb +178 -0
  25. data/lib/friendly_id/datamapper.rb +5 -0
  26. data/lib/friendly_id/railtie.rb +22 -0
  27. data/lib/friendly_id/sequel.rb +5 -0
  28. data/lib/friendly_id/slug_string.rb +25 -0
  29. data/lib/friendly_id/slugged.rb +105 -0
  30. data/lib/friendly_id/status.rb +35 -0
  31. data/lib/friendly_id/test.rb +350 -0
  32. data/lib/friendly_id/version.rb +9 -0
  33. data/lib/generators/friendly_id_generator.rb +25 -0
  34. data/lib/tasks/friendly_id.rake +19 -0
  35. data/rails/init.rb +2 -0
  36. data/test/active_record_adapter/ar_test_helper.rb +150 -0
  37. data/test/active_record_adapter/basic_slugged_model_test.rb +14 -0
  38. data/test/active_record_adapter/cached_slug_test.rb +76 -0
  39. data/test/active_record_adapter/core.rb +138 -0
  40. data/test/active_record_adapter/custom_normalizer_test.rb +20 -0
  41. data/test/active_record_adapter/custom_table_name_test.rb +22 -0
  42. data/test/active_record_adapter/default_scope_test.rb +30 -0
  43. data/test/active_record_adapter/optimistic_locking_test.rb +18 -0
  44. data/test/active_record_adapter/scoped_model_test.rb +119 -0
  45. data/test/active_record_adapter/simple_test.rb +76 -0
  46. data/test/active_record_adapter/slug_test.rb +34 -0
  47. data/test/active_record_adapter/slugged.rb +33 -0
  48. data/test/active_record_adapter/slugged_status_test.rb +28 -0
  49. data/test/active_record_adapter/sti_test.rb +22 -0
  50. data/test/active_record_adapter/support/database.jdbcsqlite3.yml +2 -0
  51. data/test/active_record_adapter/support/database.mysql.yml +4 -0
  52. data/test/active_record_adapter/support/database.postgres.yml +6 -0
  53. data/test/active_record_adapter/support/database.sqlite3.yml +2 -0
  54. data/test/active_record_adapter/support/models.rb +104 -0
  55. data/test/active_record_adapter/tasks_test.rb +82 -0
  56. data/test/friendly_id_test.rb +96 -0
  57. data/test/test_helper.rb +13 -0
  58. metadata +193 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2008-2010 Norman Clarke, Adrian Mugnolo and Emilio Tagua.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # FriendlyId
2
+
3
+ FriendlyId is the "Swiss Army bulldozer" of slugging and permalink plugins for
4
+ Ruby on Rails. It allows you to create pretty URL's and work with
5
+ human-friendly strings as if they were numeric ids for Active Record models.
6
+
7
+ Using FriendlyId, it's easy to make your application use URL's like:
8
+
9
+ http://example.com/states/washington
10
+
11
+ instead of:
12
+
13
+ http://example.com/states/4323454
14
+
15
+ ## FriendlyId Features
16
+
17
+ FriendlyId offers many advanced features, including: slug history and
18
+ versioning, scoped slugs, reserved words, custom slug generators, and
19
+ excellent Unicode support. For complete information on using FriendlyId,
20
+ please see the [FriendlyId Guide](http://norman.github.com/friendly_id/file.Guide.html).
21
+
22
+ FriendlyId is compatible with Active Record **2.3.x** and **3.0**.
23
+
24
+ ## Docs, Info and Support
25
+
26
+ * [FriendlyId Guide](http://norman.github.com/friendly_id/file.Guide.html)
27
+ * [API Docs](http://norman.github.com/friendly_id)
28
+ * [Google Group](http://groups.google.com/group/friendly_id)
29
+ * [Source Code](http://github.com/norman/friendly_id/)
30
+ * [Issue Tracker](http://github.com/norman/friendly_id/issues)
31
+
32
+ ## Rails Quickstart
33
+
34
+ Note that the example below uses Rails 3. But don't worry: FriendlyId will
35
+ continue to support 2.3.x until Rails 3.1 is released.
36
+
37
+ gem install friendly_id
38
+
39
+ rails new my_app
40
+
41
+ cd my_app
42
+
43
+ # add to Gemfile
44
+ gem "friendly_id", "~> 3.2"
45
+
46
+ rails generate friendly_id
47
+ rails generate scaffold user name:string cached_slug:string
48
+
49
+ rake db:migrate
50
+
51
+ # edit app/models/user.rb
52
+ class User < ActiveRecord::Base
53
+ has_friendly_id :name, :use_slug => true
54
+ end
55
+
56
+ User.create! :name => "Joe Schmoe"
57
+
58
+ rails server
59
+
60
+ GET http://0.0.0.0:3000/users/joe-schmoe
61
+
62
+ ## Sequel and DataMapper, too
63
+
64
+ [Alex Coles](http://github.com/myabc) maintains an implemntation of
65
+ [FriendlyId for DataMapper](http://github.com/myabc/friendly_id_datamapper) that supports almost
66
+ all the features of the Active Record version.
67
+
68
+ Norman Clarke maintains an implementation of
69
+ [FriendlyId forSequel](http://github.com/norman/friendly_id_sequel) with some of the features
70
+ of the Active Record version.
71
+
72
+ ## Bugs
73
+
74
+ Please report them on the [Github issue tracker](http://github.com/norman/friendly_id/issues)
75
+ for this project.
76
+
77
+ If you have a bug to report, please include the following information:
78
+
79
+ * **Version information for FriendlyId, Rails and Ruby.**
80
+ * Stack trace and error message.
81
+ * Any snippets of relevant model, view or controller code that shows how your
82
+ are using FriendlyId.
83
+
84
+ If you are able to, it helps even more if you can fork FriendlyId on Github,
85
+ and add a test that reproduces the error you are experiencing.
86
+
87
+ ## Credits
88
+
89
+ FriendlyId was created by Norman Clarke, Adrian Mugnolo, and Emilio Tagua.
90
+
91
+ If you like FriendlyId, please recommend us on Working With Rails:
92
+
93
+ * [http://bit.ly/recommend-norman](http://bit.ly/recommend-norman)
94
+ * [http://bit.ly/recommend-emilio](http://bit.ly/recommend-emilio)
95
+ * [http://bit.ly/recommend-adrian](http://bit.ly/recommend-adrian)
96
+
97
+ Thanks!
98
+
99
+ Copyright (c) 2008-2010, released under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1,75 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+ require "rake"
4
+ require "rake/testtask"
5
+ require "rake/gempackagetask"
6
+ require "rake/clean"
7
+
8
+ task :default => :test
9
+
10
+ CLEAN << "pkg" << "doc" << "coverage" << ".yardoc"
11
+ Rake::GemPackageTask.new(eval(File.read("friendly_id.gemspec"))) { |pkg| }
12
+
13
+ begin
14
+ require "yard"
15
+ YARD::Rake::YardocTask.new do |t|
16
+ t.options = ["--output-dir=doc"]
17
+ t.options << "--files" << ["Guide.md", "Contributors.md", "Changelog.md"].join(",")
18
+ end
19
+ rescue LoadError
20
+ end
21
+
22
+ begin
23
+ require "rcov/rcovtask"
24
+ Rcov::RcovTask.new do |r|
25
+ r.test_files = FileList["test/**/*_test.rb"]
26
+ r.verbose = true
27
+ r.rcov_opts << "--exclude gems/*"
28
+ end
29
+ rescue LoadError
30
+ end
31
+
32
+
33
+ Rake::TestTask.new(:test) { |t| t.pattern = "test/**/*_test.rb" }
34
+
35
+ namespace :test do
36
+ task :rails do
37
+ rm_rf "fid"
38
+ sh "rails --template extras/template-gem.rb fid"
39
+ sh "cd fid; rake test"
40
+ end
41
+ Rake::TestTask.new(:friendly_id) { |t| t.pattern = "test/*_test.rb" }
42
+ Rake::TestTask.new(:ar) { |t| t.pattern = "test/active_record_adapter/*_test.rb" }
43
+
44
+ desc "Test against lots of versions"
45
+ task :pre_release do
46
+ ["ree-1.8.7-2010.02", "ruby-1.9.2-p0"].each do |ruby|
47
+ ["sqlite3", "mysql", "postgres"].each do |driver|
48
+ [2, 3].each do |ar_version|
49
+ command = "rake-#{ruby} test AR=#{ar_version} DB=#{driver}"
50
+ puts command
51
+ puts `#{command}`
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ namespace :rails do
58
+ task :plugin do
59
+ rm_rf "fid"
60
+ sh "rails --template extras/template-plugin.rb fid"
61
+ sh "cd fid; rake test"
62
+ end
63
+ end
64
+ end
65
+
66
+ task :pushdocs do
67
+ branch = `git branch | grep "*"`.chomp.gsub("* ", "")
68
+ sh "git stash"
69
+ sh "git checkout gh-pages"
70
+ sh "cp -rp doc/* ."
71
+ sh 'git commit -a -m "Regenerated docs"'
72
+ sh "git push origin gh-pages"
73
+ sh "git checkout #{branch}"
74
+ sh "git stash apply"
75
+ end
data/extras/README.txt ADDED
@@ -0,0 +1,3 @@
1
+ These templates are here to generate FriendlyId-enabled Rails apps for
2
+ testing. They are for developers, they are not intended for generating
3
+ "real" applications.
data/extras/bench.rb ADDED
@@ -0,0 +1,40 @@
1
+ $:.unshift File.expand_path("../lib", File.dirname(__FILE__))
2
+ $:.unshift File.expand_path(File.dirname(__FILE__))
3
+ $:.uniq!
4
+
5
+ require "extras"
6
+ require 'rbench'
7
+ FACTOR = 10
8
+
9
+ RBench.run(TIMES) do
10
+
11
+ column :times
12
+ column :default
13
+ column :no_slug
14
+ column :slug
15
+ column :cached_slug
16
+
17
+ report 'find model by id', (TIMES * FACTOR).ceil do
18
+ default { User.find(get_id) }
19
+ no_slug { User.find(USERS.rand) }
20
+ slug { Post.find(POSTS.rand) }
21
+ cached_slug { District.find(DISTRICTS.rand) }
22
+ end
23
+
24
+ report 'find model using array of ids', (TIMES * FACTOR).ceil do
25
+ default { User.find(get_id(2)) }
26
+ no_slug { User.find(USERS.rand(2)) }
27
+ slug { Post.find(POSTS.rand(2)) }
28
+ cached_slug { District.find(DISTRICTS.rand(2)) }
29
+ end
30
+
31
+ report 'find model using id, then to_param', (TIMES * FACTOR).ceil do
32
+ default { User.find(get_id).to_param }
33
+ no_slug { User.find(USERS.rand).to_param }
34
+ slug { Post.find(POSTS.rand).to_param }
35
+ cached_slug { District.find(DISTRICTS.rand).to_param }
36
+ end
37
+
38
+ summary 'Total'
39
+
40
+ end
data/extras/extras.rb ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby -KU
2
+ require File.dirname(__FILE__) + '/../test/test_helper'
3
+ require File.dirname(__FILE__) + '/../test/active_record_adapter/ar_test_helper'
4
+ require 'ffaker'
5
+
6
+ TIMES = (ENV['N'] || 100).to_i
7
+ POSTS = []
8
+ DISTRICTS = []
9
+ USERS = []
10
+
11
+ User.delete_all
12
+ Post.delete_all
13
+ District.delete_all
14
+ Slug.delete_all
15
+
16
+ 100.times do
17
+ name = Faker::Name.name
18
+ USERS << (User.create! :name => name).friendly_id
19
+ POSTS << (Post.create! :name => name).friendly_id
20
+ DISTRICTS << (District.create! :name => name).friendly_id
21
+ end
22
+
23
+ def get_id(returns = 1)
24
+ (1..100).to_a.rand(returns)
25
+ end
26
+
27
+ class Array
28
+ def rand(returns = 1)
29
+ @return = []
30
+ returns.times do
31
+ until @return.length == returns do
32
+ val = self[Kernel.rand(length)]
33
+ @return << val unless @return.include? val
34
+ end
35
+ end
36
+ return returns == 1 ? @return.first : @return
37
+ end
38
+ end
data/extras/prof.rb ADDED
@@ -0,0 +1,19 @@
1
+ $:.unshift File.expand_path("../lib", File.dirname(__FILE__))
2
+ $:.unshift File.expand_path(File.dirname(__FILE__))
3
+ $:.uniq!
4
+
5
+ require "extras"
6
+ require 'ruby-prof'
7
+
8
+ # RubyProf.measure_mode = RubyProf::MEMORY
9
+ GC.disable
10
+ RubyProf.start
11
+ 100.times do
12
+ Post.find(slug = POSTS.rand)
13
+ end
14
+ result = RubyProf.stop
15
+ GC.enable
16
+ # printer = RubyProf::CallTreePrinter.new(result)
17
+ printer = RubyProf::GraphPrinter.new(result)
18
+ version = ActiveRecord::VERSION::STRING.gsub(".", "")
19
+ printer.print(File.new("prof#{version}.txt", "w"))
@@ -0,0 +1,26 @@
1
+ run "rm public/index.html"
2
+ gem "friendly_id"
3
+ gem "haml"
4
+ gem "will_paginate"
5
+ run "haml --rails ."
6
+ generate "friendly_id"
7
+ generate :haml_scaffold, "post title:string"
8
+ route "map.root :controller => 'posts', :action => 'index'"
9
+ rake "db:migrate"
10
+ rake "db:fixtures:load"
11
+ file 'app/models/post.rb',
12
+ %q{class Post < ActiveRecord::Base
13
+ has_friendly_id :title, :use_slug => true
14
+ end}
15
+ file 'test/fixtures/slugs.yml',
16
+ %q{
17
+ one:
18
+ name: mystring
19
+ sequence: 1
20
+ sluggable: one (Post)
21
+
22
+ two:
23
+ name: mystring
24
+ sequence: 1
25
+ sluggable: two (Post)
26
+ }
@@ -0,0 +1,28 @@
1
+ run "rm public/index.html"
2
+ inside 'vendor/plugins' do
3
+ run "git clone ../../../ friendly_id"
4
+ end
5
+ gem "haml"
6
+ gem "will_paginate"
7
+ run "haml --rails ."
8
+ generate "friendly_id"
9
+ generate :haml_scaffold, "post title:string"
10
+ route "map.root :controller => 'posts', :action => 'index'"
11
+ rake "db:migrate"
12
+ rake "db:fixtures:load"
13
+ file 'app/models/post.rb',
14
+ %q{class Post < ActiveRecord::Base
15
+ has_friendly_id :title, :use_slug => true
16
+ end}
17
+ file 'test/fixtures/slugs.yml',
18
+ %q{
19
+ one:
20
+ name: mystring
21
+ sequence: 1
22
+ sluggable: one (Post)
23
+
24
+ two:
25
+ name: mystring
26
+ sequence: 2
27
+ sluggable: two (Post)
28
+ }
@@ -0,0 +1,30 @@
1
+ class FriendlyIdGenerator < Rails::Generator::Base
2
+
3
+ RAKE_TASKS = File.join("..", "..", "..", "lib", "tasks", "friendly_id.rake")
4
+
5
+ def manifest
6
+ record do |m|
7
+ unless options[:skip_migration]
8
+ m.migration_template('create_slugs.rb', 'db/migrate', :migration_file_name => 'create_slugs')
9
+ end
10
+ unless options[:skip_tasks]
11
+ m.directory "lib/tasks"
12
+ m.file RAKE_TASKS, "lib/tasks/friendly_id.rake"
13
+ end
14
+ end
15
+ end
16
+
17
+ protected
18
+
19
+ def add_options!(opt)
20
+ opt.separator ''
21
+ opt.separator 'Options:'
22
+ opt.on("--skip-migration", "Don't generate a migration for the slugs table") do |value|
23
+ options[:skip_migration] = value
24
+ end
25
+ opt.on("--skip-tasks", "Don't add friendly_id Rake tasks to lib/tasks") do |value|
26
+ options[:skip_tasks] = value
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,18 @@
1
+ class CreateSlugs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :slugs do |t|
4
+ t.string :name
5
+ t.integer :sluggable_id
6
+ t.integer :sequence, :null => false, :default => 1
7
+ t.string :sluggable_type, :limit => 40
8
+ t.string :scope
9
+ t.datetime :created_at
10
+ end
11
+ add_index :slugs, :sluggable_id
12
+ add_index :slugs, [:name, :sluggable_type, :sequence, :scope], :name => "index_slugs_on_n_s_s_and_s", :unique => true
13
+ end
14
+
15
+ def self.down
16
+ drop_table :slugs
17
+ end
18
+ end
@@ -0,0 +1,93 @@
1
+ require "babosa"
2
+ require "forwardable"
3
+ require "friendly_id/slug_string"
4
+ require "friendly_id/configuration"
5
+ require "friendly_id/status"
6
+ require "friendly_id/slugged"
7
+
8
+ # FriendlyId is a comprehensive Ruby library for slugging and permalinks with
9
+ # ActiveRecord.
10
+ # @author Norman Clarke
11
+ # @author Emilio Tagua
12
+ # @author Adrian Mugnolo
13
+ module FriendlyId
14
+
15
+ # An error based on this class is raised when slug generation fails
16
+ class SlugGenerationError < StandardError ; end
17
+
18
+ # Raised when the slug text is blank.
19
+ class BlankError < SlugGenerationError ; end
20
+
21
+ # Raised when the slug text is reserved.
22
+ class ReservedError < SlugGenerationError ; end
23
+
24
+ module Base
25
+ # Set up a model to use a friendly_id. This method accepts a hash with
26
+ # {FriendlyId::Configuration several possible options}.
27
+ #
28
+ # @param [#to_sym] method The column or method that should be used as the
29
+ # basis of the friendly_id string.
30
+ #
31
+ # @param [Hash] options For valid configuration options, see
32
+ # {FriendlyId::Configuration}.
33
+ #
34
+ # @example
35
+ #
36
+ # class User < ActiveRecord::Base
37
+ # has_friendly_id :user_name
38
+ # end
39
+ #
40
+ # class Post < ActiveRecord::Base
41
+ # has_friendly_id :title, :use_slug => true, :approximate_ascii => true
42
+ # end
43
+ #
44
+ # @see FriendlyId::Configuration
45
+ def has_friendly_id(method, options = {})
46
+ raise NotImplementedError
47
+ end
48
+
49
+ # Does the model class use the FriendlyId plugin?
50
+ def uses_friendly_id?
51
+ respond_to? :friendly_id_config
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ class String
58
+ def parse_friendly_id(separator = nil)
59
+ separator ||= FriendlyId::Configuration::DEFAULTS[:sequence_separator]
60
+ name, sequence = split(/#{Regexp.escape(separator)}(\d+)?\z/)
61
+ return name, (sequence ||= 1).to_i
62
+ end
63
+ end
64
+
65
+ class Object
66
+
67
+ # Is the object a friendly id? Note that the return value here is
68
+ # +false+ if the +id+ is definitely not friendly, and +nil+ if it can
69
+ # not be determined.
70
+ # The return value will be:
71
+ # * +true+ - if the id is definitely friendly (i.e., a string with non-numeric characters)
72
+ # * +false+ - if the id is definitely unfriendly (i.e., an Integer, a model instance, etc.)
73
+ # * +nil+ - if it can not be determined (i.e., a numeric string like "206".)
74
+ # @return [true, false, nil]
75
+ # @see #unfriendly?
76
+ def friendly_id?
77
+ if kind_of?(Integer) or kind_of?(Symbol) or self.class.respond_to? :friendly_id_config
78
+ false
79
+ elsif to_i.to_s != to_s
80
+ true
81
+ end
82
+ end
83
+
84
+ # Is the object a numeric id?
85
+ # @return [true, false, nil] +true+ if definitely unfriendly, +false+ if
86
+ # definitely friendly, else +nil+.
87
+ # @see #friendly?
88
+ def unfriendly_id?
89
+ val = friendly_id? ; !val unless val.nil?
90
+ end
91
+ end
92
+
93
+ require "friendly_id/railtie" if defined?(Rails) && Rails.version >= "3"