kieran-dm-is-slug 0.9.11

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 @@
1
+
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Aaron Qian
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,12 @@
1
+ History.txt
2
+ LICENSE
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ TODO
7
+ lib/dm-is-slug.rb
8
+ lib/dm-is-slug/is/slug.rb
9
+ lib/dm-is-slug/is/version.rb
10
+ spec/integration/slug_spec.rb
11
+ spec/spec.opts
12
+ spec/spec_helper.rb
@@ -0,0 +1,150 @@
1
+ dm-is-slug
2
+ ==========
3
+
4
+
5
+ DataMapper plugin for creating and slugs (and permalinks).
6
+
7
+
8
+ Basics
9
+ ------
10
+
11
+ Slugs are unique identifiers in a url that endeavour to be more human-readable.
12
+
13
+ Say you have a blog where you like to write about Ruby (it's a long shot, I know). You've just written an insigtful expository on DataMapper, and you're ready to pass that URL around for people to read.
14
+
15
+ This gem will turn:
16
+
17
+ /category/4/posts/12
18
+
19
+ into:
20
+
21
+ /category/ruby/posts/datamapper_is_the_bees_knees
22
+
23
+ Now the whole world will know exactly what you're sending them. Isn't that nice? The answer is "yes".
24
+
25
+
26
+ Getting started
27
+ ---------------
28
+
29
+ Let's say we have a post-class, and we want to generate permalinks or slugs for all posts.
30
+
31
+ class Post
32
+ include DataMapper::Resource
33
+
34
+ property :id, Serial
35
+ property :title, String
36
+ property :content, Text
37
+
38
+ belongs_to :user
39
+
40
+ # here we define that it should have a slug that uses title as the slug
41
+ # it will generate an extra slug property of String type, with the same size as title
42
+ is :slug, :source => :title
43
+ end
44
+
45
+ Let's Say we need to define a slug based on a method instead of a property.
46
+
47
+ class User
48
+ include DataMapper::Resource
49
+
50
+ property :id, Serial
51
+ property :email, String
52
+ property :password, String
53
+
54
+ has n, :posts
55
+
56
+ # we only want to strip out the domain name
57
+ # and use only the email account name as the permalink
58
+ def slug_for_email
59
+ email.split("@").first
60
+ end
61
+
62
+ # here we define that it should have a slug that uses title as the permalink
63
+ # it will generate an extra slug property of String type, with the same size as title
64
+ is :slug, :source => :slug_for_email, :size => 255
65
+ end
66
+
67
+ You can now find objects by slug like this:
68
+
69
+ post = Post.first(:slug => "your_slug")
70
+
71
+
72
+ Merb routes
73
+ -----------
74
+
75
+ Building pretty routes in Merb is dead simple, especially with all this slugtacular mojo going on.
76
+
77
+ Here's a quick example route:
78
+
79
+ match("/posts/:slug").to(:controller=>:posts,:action=:index).name(:post)
80
+
81
+ Let's make a quick post to our fictional blog:
82
+
83
+ Post.create(:title => "Pretty URLs in Merb are easy", :content => "I feel like a good person for making the Internets pretty.")
84
+
85
+ Now the URL generation is as easy as:
86
+
87
+ url(:post,@post) #=> /posts/pretty_urls_in_merb_are_easy
88
+
89
+ Pretty slick, no?
90
+
91
+
92
+ Plays nice with nested routes and resources
93
+ -------------------------------------------
94
+
95
+ Say we want to have pretty URLs for a forum (and who wouldn't?)
96
+
97
+ First, let's set up a couple of models:
98
+
99
+ class Forum
100
+ include DataMapper::Resource
101
+
102
+ property :id, Serial
103
+ property :name, String
104
+ property :description, Text
105
+
106
+ is :slug, :source => :name
107
+ end
108
+
109
+ class Topic
110
+ include DataMapper::Resource
111
+
112
+ property :id, Serial
113
+ property :subject, String
114
+ property :description, Text
115
+
116
+ is :slug, :source => :subject
117
+ end
118
+
119
+ OK, now we'll make some nested resources in Merb in router.rb:
120
+
121
+ resources :forums, :identify => :forum_slug do
122
+ resources :topics, :identify => :topic_slug
123
+ end
124
+
125
+ This will generate CRUD routes that match the following pattern:
126
+
127
+ /forums/:forum_slug/topics/:topic_slug
128
+
129
+ Since \#forum\_slug and \#topic\_slug are aliases for \#slug (both getters & setters), in your resource controller you can get the models via:
130
+
131
+ @forum = Forum.get(params[:forum_slug])
132
+
133
+ @topic = Topic.get(params[:topic_slug])
134
+
135
+ and generating the URL is as easy as:
136
+
137
+ resource(@forum,@topic)
138
+
139
+
140
+ Mutability
141
+ ----------
142
+
143
+ By default, all slugs are mutable. That is, they can (and will) be updated when the source property changes.
144
+
145
+ If you want to make a slug immutable (a permalink), you can pass :mutable => false as an option:
146
+
147
+ is :slug, :source => :name, :mutable => false
148
+
149
+ Now your slug will never change once created.
150
+
@@ -0,0 +1,54 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require 'spec/rake/spectask'
6
+ require 'pathname'
7
+
8
+ ROOT = Pathname(__FILE__).dirname.expand_path
9
+ require ROOT + 'lib/dm-is-slug/is/version'
10
+
11
+ AUTHOR = "Aaron Qian, Nik Radford"
12
+ EMAIL = "aaron [a] ekohe [d] com; nik [a] terminaldischarge [d] net"
13
+ GEM_NAME = "dm-is-slug"
14
+ GEM_VERSION = DataMapper::Is::Slug::VERSION
15
+ GEM_DEPENDENCIES = [["dm-core", "~>0.9"]]
16
+ GEM_CLEAN = ["log", "pkg"]
17
+ GEM_EXTRAS = { :has_rdoc => false }
18
+
19
+ PROJECT_NAME = "dm-is-slug"
20
+ PROJECT_URL = "http://github.com/aq1018/dm-is-slug"
21
+ PROJECT_DESCRIPTION = PROJECT_SUMMARY = "DataMapper plugin that generates unique slugs"
22
+
23
+ require 'tasks/hoe'
24
+
25
+ task :default => [ :spec ]
26
+
27
+ WIN32 = (RUBY_PLATFORM =~ /win32|mingw|cygwin/) rescue nil
28
+ SUDO = WIN32 ? '' : ('sudo' unless ENV['SUDOLESS'])
29
+
30
+ desc "Install #{GEM_NAME} #{GEM_VERSION}"
31
+ task :install => [ :package ] do
32
+ sh "#{SUDO} gem install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources", :verbose => false
33
+ end
34
+
35
+ desc "Uninstall #{GEM_NAME} #{GEM_VERSION} (default ruby)"
36
+ task :uninstall => [ :clobber ] do
37
+ sh "#{SUDO} gem uninstall #{GEM_NAME} -v#{GEM_VERSION} -I -x", :verbose => false
38
+ end
39
+
40
+ desc 'Run specifications'
41
+ Spec::Rake::SpecTask.new(:spec) do |t|
42
+ t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
43
+ t.spec_files = Pathname.glob(Pathname.new(__FILE__).dirname + 'spec/**/*_spec.rb')
44
+
45
+ begin
46
+ t.rcov = ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true
47
+ t.rcov_opts << '--exclude' << 'spec'
48
+ t.rcov_opts << '--text-summary'
49
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
50
+ rescue Exception
51
+ puts 'rcov is not installed. Please install before continuing'
52
+ exit
53
+ end
54
+ end
data/TODO ADDED
@@ -0,0 +1,4 @@
1
+ TODO
2
+ ====
3
+
4
+ Docs??
@@ -0,0 +1,36 @@
1
+ # Needed to import datamapper and other gems
2
+ require 'rubygems'
3
+ require 'pathname'
4
+ require 'iconv'
5
+
6
+ # Add all external dependencies for the plugin here
7
+ gem 'dm-core', '~>0.9.9'
8
+ require 'dm-core'
9
+
10
+ require Pathname(__FILE__).dirname.expand_path / 'dm-is-slug' / 'is' / 'version.rb'
11
+
12
+ # Require plugin-files
13
+ require Pathname(__FILE__).dirname.expand_path / 'dm-is-slug' / 'is' / 'slug.rb'
14
+
15
+ # Include the plugin in Resource
16
+ module DataMapper
17
+ module Resource
18
+ module ClassMethods
19
+ include DataMapper::Is::Slug
20
+ end # module ClassMethods
21
+ end # module Resource
22
+ end # module DataMapper
23
+
24
+ # Include DataMapper::Model#get and DataMapper::Collection#get override
25
+ # So we do user.posts.get("my-shinny-new-post")
26
+
27
+ module DataMapper
28
+ module Model
29
+ include DataMapper::Is::Slug::AliasMethods
30
+ end
31
+
32
+ class Collection
33
+ include DataMapper::Is::Slug::AliasMethods
34
+ end
35
+ end
36
+
@@ -0,0 +1,207 @@
1
+ module DataMapper
2
+ module Is
3
+ module Slug
4
+ class InvalidSlugSource < Exception
5
+ end
6
+
7
+ DEFAULT_SLUG_SIZE = 50
8
+
9
+ DEFAULT_SLUG_OPTIONS = {
10
+ :mutable => true,
11
+ :separator => '_'
12
+ }
13
+
14
+ ##
15
+ # Overriding the default Slug separator "-" with "_"
16
+ # I find it makes URIs much more readable
17
+ # method from dm-types/slug
18
+ ##
19
+
20
+ # @param [String] str A string to escape for use as a slug
21
+ # @return [String] an URL-safe string
22
+ def self.escape(string)
23
+ separator = DEFAULT_SLUG_OPTIONS[:separator]
24
+
25
+ # swap accented characters with their counterparts
26
+ string.gsub!(/[èÈééÉêÊëË]/,'e')
27
+ string.gsub!(/[àÀáÁâÂãÃäÄåÅ]/,'a')
28
+ string.gsub!(/[ìÌíÍîÎïÏ]/,'i')
29
+ string.gsub!(/[òÒóÓöÖôÔõÕøØ]/,'o')
30
+ string.gsub!(/[ùÙúÚûÛüÜ]/,'u')
31
+ string.gsub!(/[ýÝÿ]/,'y')
32
+ string.gsub!(/[çÇ]/,'c')
33
+ string.gsub!(/[ñÑ]/,'n')
34
+ string.gsub!(/[Ð]/,'d')
35
+
36
+ result = Iconv.iconv('ascii//translit//IGNORE', 'utf-8', string).to_s
37
+ result.gsub!(/[^\x00-\x7F]+/, '') # Remove anything non-ASCII entirely (e.g. diacritics).
38
+ result.strip!
39
+ result.downcase!
40
+ result.gsub!(/\b&\b/, 'and') # Change & to a more slug-friendly character.
41
+ result.gsub!(/[^\w_ \-]+/i, '') # Remove unwanted chars.
42
+ result.gsub!(/\ +/, separator) # contract multiple spaces.
43
+ result.gsub!(Regexp.new("#{separator}+"), separator) # No more than one separator in a row. # result.gsub!(/_+/i, separator)
44
+ result.gsub!(Regexp.new("^#{separator}|#{separator}$"), separator) # Remove leading/trailing separators. # result.gsub!(/^_|_$/i, '')
45
+ result
46
+ end
47
+
48
+ ##
49
+ # Methods that should be included in DataMapper::Model.
50
+ # Normally this should just be your generator, so that the namespace
51
+ # does not get cluttered. ClassMethods and InstanceMethods gets added
52
+ # in the specific resources when you fire is :slug
53
+ ##
54
+
55
+ # Defines a +slug+ property on your model with the same size as your
56
+ # source property. This property is Unicode escaped, and treated so as
57
+ # to be fit for use in URLs.
58
+ #
59
+ # ==== Example
60
+ # Suppose your source attribute was the following string: "Hot deals on
61
+ # Boxing Day". This string would be escaped to "hot_deals_on_boxing_day".
62
+ #
63
+ # Non-ASCII characters are attempted to be converted to their nearest
64
+ # approximate.
65
+ #
66
+ # ==== Parameters
67
+ # +mutable+::
68
+ # If a slug is mutable it will be updated as the source field changes.
69
+ # Setting this to false will make the slug immutable (permanent)
70
+ # +source+::
71
+ # The property on the model to use as the source of the generated slug,
72
+ # or an instance method defined in the model, the method must return
73
+ # a string or nil.
74
+ # +size+::
75
+ # The length of the +slug+ property
76
+ #
77
+ # @param [Hash] provide options in a Hash. See *Parameters* for details
78
+ def is_slug(options)
79
+ extend DataMapper::Is::Slug::ClassMethods
80
+ include DataMapper::Is::Slug::InstanceMethods
81
+
82
+ @slug_options = DEFAULT_SLUG_OPTIONS.merge(options)
83
+ raise InvalidSlugSource('You must specify a :source to generate slug.') unless slug_source
84
+
85
+ slug_options[:size] ||= get_slug_size
86
+ property(:slug, String, :size => slug_options[:size], :unique => true) unless slug_property
87
+ before :save, :generate_slug
88
+
89
+ # add alternate slug names for nested resources
90
+ # e.g. /forums/:forum_slug/topics/:topic_slug/
91
+ class_eval <<-SLUG
92
+ def #{self.new.class.to_s.snake_case}_slug
93
+ slug
94
+ end
95
+ def #{self.new.class.to_s.snake_case}_slug=(str)
96
+ self.slug = str
97
+ end
98
+ SLUG
99
+ end
100
+
101
+ module ClassMethods
102
+ attr_reader :slug_options
103
+
104
+ def slug_mutable?
105
+ slug_options[:mutable]
106
+ end
107
+
108
+ def slug_source
109
+ slug_options[:source] ? slug_options[:source].to_sym : nil
110
+ end
111
+
112
+ def slug_source_property
113
+ detect_slug_property_by_name(slug_source)
114
+ end
115
+
116
+ def slug_property
117
+ detect_slug_property_by_name(:slug)
118
+ end
119
+
120
+ private
121
+
122
+ def detect_slug_property_by_name(name)
123
+ properties.detect do |p|
124
+ p.name == name && p.type == String
125
+ end
126
+ end
127
+
128
+ def get_slug_size
129
+ slug_source_property && slug_source_property.size || DataMapper::Is::Slug::DEFAULT_SLUG_SIZE
130
+ end
131
+ end # ClassMethods
132
+
133
+ module InstanceMethods
134
+ def to_param
135
+ [slug]
136
+ end
137
+
138
+ def slug_mutable?
139
+ self.class.slug_mutable?
140
+ end
141
+
142
+ def slug_source
143
+ self.class.slug_source
144
+ end
145
+
146
+ def slug_source_property
147
+ self.class.slug_source_property
148
+ end
149
+
150
+ def slug_property
151
+ self.class.slug_property
152
+ end
153
+
154
+ def slug_source_value
155
+ self.send(slug_source)
156
+ end
157
+
158
+ # The slug is not stale if
159
+ # 1. the slug is permanent, and slug column has something valid in it
160
+ # 2. the slug source value is nil or empty
161
+ def stale_slug?
162
+ !((!slug_mutable? && slug && !slug.empty?) || (slug_source_value.nil? || slug_source_value.empty?))
163
+ end
164
+
165
+ private
166
+
167
+ def make_unique_slug!
168
+ unique_slug = DataMapper::Is::Slug.escape(slug_source_value)
169
+
170
+ # see if there are other records with the same slug (enables #save!)
171
+ unique_slug = "#{unique_slug}-2" if self.class.first(:slug => unique_slug, :id.not => self.id)
172
+
173
+ while(self.class.first(:slug => unique_slug, :id.not => self.id))
174
+ i = unique_slug[-1..-1].to_i + 1
175
+ unique_slug = unique_slug[0..-2] + i.to_s
176
+ end
177
+ unique_slug
178
+ end
179
+
180
+ def generate_slug
181
+ raise InvalidSlugSource('Invalid slug source.') unless slug_source_property || self.respond_to?(slug_source)
182
+ return unless stale_slug?
183
+ self.slug = make_unique_slug!
184
+ end
185
+ end # InstanceMethods
186
+
187
+ module AliasMethods
188
+ # override the old get method so that it looks for slugs first
189
+ # and call the old get if slug is not found
190
+ def get_with_slug(*key)
191
+ if respond_to?(:slug_options) && slug_options && key[0].to_s.to_i.to_s != key[0].to_s
192
+ first(:slug => key[0])
193
+ else
194
+ get_without_slug(*key)
195
+ end
196
+ end
197
+
198
+ ##
199
+ # fired when your plugin gets included into Resource
200
+ def self.included(base)
201
+ base.send :alias_method, :get_without_slug, :get
202
+ base.send :alias_method, :get, :get_with_slug
203
+ end
204
+ end
205
+ end # Slug
206
+ end # Is
207
+ end # DataMapper
@@ -0,0 +1,7 @@
1
+ module DataMapper
2
+ module Is
3
+ module Slug
4
+ VERSION = "0.9.11"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,180 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
5
+ describe 'DataMapper::Is::Slug' do
6
+
7
+ class User
8
+ include DataMapper::Resource
9
+
10
+ property :id, Serial
11
+ property :email, String
12
+ has n, :posts
13
+ has n, :todos
14
+
15
+ def slug_for_email
16
+ email.split("@").first
17
+ end
18
+
19
+ is :slug, :source => :slug_for_email, :size => 80
20
+ end
21
+
22
+ class Post
23
+ include DataMapper::Resource
24
+
25
+ property :id, Serial
26
+ property :title, String, :size => 2000
27
+ property :content, Text
28
+
29
+ belongs_to :user
30
+
31
+ is :slug, :source => :title, :mutable => false
32
+ end
33
+
34
+ class Todo
35
+ include DataMapper::Resource
36
+ property :id, Serial
37
+ property :title, String
38
+
39
+ belongs_to :user
40
+ end
41
+
42
+ before :all do
43
+ User.auto_migrate!(:default)
44
+ Post.auto_migrate!(:default)
45
+ Todo.auto_migrate!(:default)
46
+
47
+ @u1 = User.create(:email => "john@ekohe.com")
48
+ @p1 = Post.create(:user => @u1, :title => "My first shiny blog post")
49
+ @p2 = Post.create(:user => @u1, :title => "My second shiny blog post")
50
+ @p3 = Post.create(:user => @u1, :title => "My third shiny blog post")
51
+
52
+ @u2 = User.create(:email => "john@someotherplace.com")
53
+ @p4 = Post.create(:user => @u2, :title => "My first Shiny blog post")
54
+ @p5 = Post.create(:user => @u2, :title => "i heart merb and dm")
55
+ @p6 = Post.create(:user => @u2, :title => "another productive day!!")
56
+ @p7 = Post.create(:user => @u2, :title => "another productive day!!")
57
+ @p8 = Post.create(:user => @u2, :title => "another productive day!!")
58
+ @p9 = Post.create(:user => @u2, :title => "another productive day!!")
59
+ @p10 = Post.create(:user => @u2, :title => "another productive day!!")
60
+ @p11 = Post.create(:user => @u2, :title => "another productive day!!")
61
+ @p12 = Post.create(:user => @u2, :title => "another productive day!!")
62
+ @p13 = Post.create(:user => @u2, :title => "another productive day!!")
63
+ @p14 = Post.create(:user => @u2, :title => "another productive day!!")
64
+ @p15 = Post.create(:user => @u2, :title => "another productive day!!")
65
+ @p16 = Post.create(:user => @u2, :title => "another productive day!!")
66
+ @p17 = Post.create(:user => @u2, :title => "A fancy café")
67
+ end
68
+
69
+ it "should generate slugs" do
70
+ User.all.each do |u|
71
+ u.slug.should_not be_nil
72
+ end
73
+
74
+ Post.all.each do |p|
75
+ p.slug.should_not be_nil
76
+ end
77
+ end
78
+
79
+ it "should generate unique slugs" do
80
+ @u1.slug.should_not == @u2.slug
81
+ @p1.slug.should_not == @p4.slug
82
+ end
83
+
84
+ it "should generate correct slug for user" do
85
+ @u1.slug.should == "john"
86
+ @u2.slug.should == "john-2"
87
+ end
88
+
89
+ it "should generate correct slug for post" do
90
+ @p1.slug.should == "my_first_shiny_blog_post"
91
+ @p2.slug.should == "my_second_shiny_blog_post"
92
+ @p3.slug.should == "my_third_shiny_blog_post"
93
+ @p4.slug.should == "my_first_shiny_blog_post-2"
94
+ @p5.slug.should == "i_heart_merb_and_dm"
95
+ @p6.slug.should == "another_productive_day"
96
+ @p7.slug.should == "another_productive_day-2"
97
+ @p8.slug.should == "another_productive_day-3"
98
+ @p9.slug.should == "another_productive_day-4"
99
+ @p10.slug.should == "another_productive_day-5"
100
+ @p11.slug.should == "another_productive_day-6"
101
+ @p12.slug.should == "another_productive_day-7"
102
+ @p13.slug.should == "another_productive_day-8"
103
+ @p14.slug.should == "another_productive_day-9"
104
+ @p15.slug.should == "another_productive_day-10"
105
+ @p16.slug.should == "another_productive_day-11"
106
+ end
107
+
108
+ it "should update slug if :mutable => true or not specified" do
109
+ user = User.create(:email => "a_person@ekohe.com")
110
+ user.slug.should == "a_person"
111
+
112
+ user.should be_slug_mutable
113
+
114
+ user.email = "changed@ekohe.com"
115
+ user.should be_dirty
116
+
117
+ user.save.should be_true
118
+ user.slug.should == "changed"
119
+ user.destroy
120
+ end
121
+
122
+ it "should not update slug if :mutable => false" do
123
+ post = Post.create(:user => @u1, :title => "hello world!")
124
+ post.slug.should == "hello_world"
125
+ post.should_not be_slug_mutable
126
+ post.title = "hello universe!"
127
+ post.should be_dirty
128
+ post.save.should be_true
129
+ post.slug.should == "hello_world"
130
+ post.destroy
131
+ end
132
+
133
+ it "should have the right size for properties" do
134
+ user_slug_property = User.properties.detect{|p| p.name == :slug && p.type == String}
135
+ user_slug_property.should_not be_nil
136
+ user_slug_property.size.should == 80
137
+
138
+ Post.properties.detect{|p| p.name == :title && p.type == String}.size.should == 2000
139
+ post_slug_property = Post.properties.detect{|p| p.name == :slug && p.type == String}
140
+ post_slug_property.should_not be_nil
141
+ post_slug_property.size.should == 2000
142
+ end
143
+
144
+ it "should find model using get method with slug" do
145
+ u = User.get("john")
146
+ u.should_not be_nil
147
+ u.should == @u1
148
+
149
+ Post.get("my_first_shiny_blog_post").should == @p1
150
+ @u1.posts.get("my_first_shiny_blog_post").should == @p1
151
+ end
152
+
153
+ it "should output slug with to_param method" do
154
+ @u1.to_param.should == ["john"]
155
+ @p1.to_param.should == ["my_first_shiny_blog_post"]
156
+ end
157
+
158
+ it "should find model using get method using id" do
159
+ u = User.get(@u1.id)
160
+ u.should_not be_nil
161
+ u.should == @u1
162
+ end
163
+
164
+ it "should find model using get method using id with non-slug models" do
165
+ todo = Todo.create(:user => @u1, :title => "blabla")
166
+ todo.should_not be_nil
167
+
168
+ Todo.get(todo.id).should == todo
169
+ @u1.todos.get(todo.id).should == todo
170
+ end
171
+
172
+ it 'should strip unicode characters from the slug' do
173
+ @p17.slug.should == 'a_fancy_cafe'
174
+ end
175
+
176
+ it 'should have slug_property on instance' do
177
+ @p1.slug_property.should == @p1.class.properties.detect{|p| p.name == :slug}
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,2 @@
1
+ --format specdoc
2
+ --colour
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ gem 'rspec'#, '~>1.1.3'
3
+ require 'spec'
4
+ require 'pathname'
5
+ require Pathname(__FILE__).dirname.expand_path.parent + 'lib/dm-is-slug'
6
+
7
+ def load_driver(name, default_uri)
8
+ return false if ENV['ADAPTER'] != name.to_s
9
+
10
+ lib = "do_#{name}"
11
+
12
+ begin
13
+ gem lib, '~>0.9.7'
14
+ require lib
15
+ DataMapper.setup(name, ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri)
16
+ DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[name]
17
+ true
18
+ rescue Gem::LoadError => e
19
+ warn "Could not load #{lib}: #{e}"
20
+ false
21
+ end
22
+ end
23
+
24
+ ENV['ADAPTER'] ||= 'sqlite3'
25
+
26
+ HAS_SQLITE3 = load_driver(:sqlite3, 'sqlite3::memory:')
27
+ HAS_MYSQL = load_driver(:mysql, 'mysql://localhost/dm_core_test')
28
+ HAS_POSTGRES = load_driver(:postgres, 'postgres://postgres@localhost/dm_core_test')
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kieran-dm-is-slug
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.11
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Qian, Nik Radford
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-12 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: dm-core
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: "0.9"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.2
34
+ version:
35
+ description: DataMapper plugin that generates unique permalinks / slugs
36
+ email:
37
+ - aaron [a] ekohe [d] com; nik [a] terminaldischarge [d] net
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - README.markdown
46
+ files:
47
+ - History.txt
48
+ - LICENSE
49
+ - Manifest.txt
50
+ - README.markdown
51
+ - Rakefile
52
+ - TODO
53
+ - lib/dm-is-slug.rb
54
+ - lib/dm-is-slug/is/slug.rb
55
+ - lib/dm-is-slug/is/version.rb
56
+ - spec/integration/slug_spec.rb
57
+ - spec/spec.opts
58
+ - spec/spec_helper.rb
59
+ has_rdoc: false
60
+ homepage: http://github.com/kieran/dm-is-slug
61
+ post_install_message:
62
+ rdoc_options:
63
+ - --main
64
+ - README.markdown
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.2.0
83
+ signing_key:
84
+ specification_version: 2
85
+ summary: DataMapper plugin that generates unique permalinks / slugs
86
+ test_files: []
87
+