sequel_sluggable 0.0.2

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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Pavel Kunc
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.
data/README.rdoc ADDED
@@ -0,0 +1,18 @@
1
+ = sequel_sluggable
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but
13
+ bump version in a commit by itself I can ignore when I pull)
14
+ * Send me a pull request. Bonus points for topic branches.
15
+
16
+ == Copyright
17
+
18
+ Copyright (c) 2009 Pavel Kunc. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rake'
2
+
3
+ # Load this library's version information
4
+ require File.expand_path('../lib/version', __FILE__)
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.version = Sequel::Plugins::Sluggable::VERSION
10
+ gem.name = "sequel_sluggable"
11
+ gem.summary = "Sequel plugin which provides Slug functionality for model."
12
+ gem.description = gem.summary
13
+ gem.email = "pavel.kunc@gmail.com"
14
+ gem.homepage = "http://github.com/pk/sequel_sluggable"
15
+ gem.authors = ["Pavel Kunc"]
16
+ gem.add_dependency "sequel"
17
+ gem.add_development_dependency "sqlite3-ruby"
18
+ gem.add_development_dependency "rspec"
19
+ gem.add_development_dependency "yard"
20
+ end
21
+ rescue LoadError
22
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
23
+ end
24
+
25
+ require 'spec/rake/spectask'
26
+ Spec::Rake::SpecTask.new(:spec) do |spec|
27
+ spec.libs << 'lib' << 'spec'
28
+ spec.spec_files = FileList['spec/**/*_spec.rb']
29
+ end
30
+
31
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
32
+ spec.libs << 'lib' << 'spec'
33
+ spec.pattern = 'spec/**/*_spec.rb'
34
+ spec.rcov = true
35
+ end
36
+
37
+ task :spec => :check_dependencies
38
+
39
+ task :default => :spec
40
+
41
+ begin
42
+ require 'yard'
43
+ YARD::Rake::YardocTask.new
44
+ rescue LoadError
45
+ task :yardoc do
46
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
47
+ end
48
+ end
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ == TODO
2
+ * Add posibility to configure algorithm how slug is generated
3
+ * Add posibility to donfigure field which holds slug
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,92 @@
1
+ module Sequel
2
+ module Plugins
3
+
4
+ # The Sluggable plugin creates hook that automatically sets
5
+ # 'slug' field to the slugged value of the column specified
6
+ # by :source option.
7
+ #
8
+ # You need to have "target" column in your model.
9
+ module Sluggable
10
+ DEFAULT_TARGET_COLUMN = :slug
11
+
12
+ # Plugin configuration
13
+ def self.configure(model, opts={})
14
+ model.sluggable_options = opts
15
+ end
16
+
17
+ module ClassMethods
18
+ attr_reader :sluggable_options
19
+
20
+ # Finds model by slug or PK
21
+ #
22
+ # @return [Sequel::Model, nil]
23
+ def find_by_pk_or_slug(value)
24
+ value.to_s =~ /^\d+$/ ? self[value] : self.find_by_slug(value)
25
+ end
26
+
27
+ # Finds model by Slug column
28
+ #
29
+ # @return [Sequel::Model, nil]
30
+ def find_by_slug(value)
31
+ self[@sluggable_options[:target] => value.chomp]
32
+ end
33
+
34
+ # Set the plugin options
35
+ #
36
+ # Options:
37
+ # @param [Hash] plugin options
38
+ # @option source [Symbol] :Column to get value to be slugged from.
39
+ # @option target [Symbol] :Column to write value of the slug to.
40
+ # @option sluggator [Proc] :Algorithm to convert string to slug.
41
+ def sluggable_options=(options)
42
+ raise ArgumentError, "You must provide :source column" unless options[:source]
43
+ if options[:sluggator] &&
44
+ !options[:sluggator].is_a?(Symbol) &&
45
+ !options[:sluggator].respond_to?(:call)
46
+ raise ArgumentError, "If you provide :sluggator it must be Symbol or callable."
47
+ end
48
+ options[:source] = options[:source].to_sym
49
+ options[:target] = options[:target] ? options[:target].to_sym : DEFAULT_TARGET_COLUMN
50
+ @sluggable_options = options
51
+ end
52
+ end
53
+
54
+ module InstanceMethods
55
+
56
+ # Sets a slug column to the slugged value
57
+ def before_save
58
+ super
59
+ target = "#{self.class.sluggable_options[:target]}="
60
+ source = self.class.sluggable_options[:source]
61
+ self.send(target, self.send(source))
62
+ end
63
+
64
+ private
65
+
66
+ # Sets the slug to the normalized URL friendly string
67
+ #
68
+ # Compute slug for the value
69
+ #
70
+ # @param [String] String to be slugged
71
+ # @return [String]
72
+ def slug=(v)
73
+ slug = if self.class.sluggable_options[:sluggator]
74
+ self.class.sluggable_options[:sluggator].call(v, self)
75
+ else
76
+ to_slug(v)
77
+ end
78
+ super(slug)
79
+ end
80
+
81
+ # Generate slug from the passed value
82
+ #
83
+ # @param [String] String to be slugged
84
+ # @return [String]
85
+ def to_slug(v)
86
+ v.chomp.downcase.gsub(/[^a-z0-9]+/,'-')
87
+ end
88
+
89
+ end # InstanceMethods
90
+ end # Sluggable
91
+ end # Plugins
92
+ end # Sequel
@@ -0,0 +1,23 @@
1
+ module Sequel::Plugins::Sluggable::SluggableRSpecHelper
2
+ def it_should_behave_like_sluggable(klass)
3
+ it "should have slug when created" do
4
+ model = klass.make(klass.slug_source_column => 'Test String')
5
+ model.slug.should eql 'test-string'
6
+ end
7
+
8
+ it "should update slug when #{klass.slug_source_column} is updated" do
9
+ model = klass.make(klass.slug_source_column => 'Test String')
10
+ lambda { model.update(klass.slug_source_column => 'Test String Two') }.should change(model,:slug).to('test-string-two')
11
+ end
12
+
13
+ it "should find #{klass} by it's ID" do
14
+ model = klass.make(klass.slug_source_column => 'Test String')
15
+ klass.find_by_id_or_slug(model.id).should eql model
16
+ end
17
+
18
+ it "should find #{klass} by it's slug" do
19
+ model = klass.make(klass.slug_source_column => 'Test String')
20
+ klass.find_by_id_or_slug('test-string').should eql model
21
+ end
22
+ end
23
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,7 @@
1
+ module Sequel
2
+ module Plugins
3
+ module Sluggable
4
+ VERSION = '0.0.2'.freeze
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,68 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{sequel_sluggable}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Pavel Kunc"]
12
+ s.date = %q{2010-02-14}
13
+ s.description = %q{Sequel plugin which provides Slug functionality for model.}
14
+ s.email = %q{pavel.kunc@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc",
18
+ "TODO"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ ".gitignore",
23
+ "LICENSE",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "TODO",
27
+ "VERSION",
28
+ "lib/sequel_sluggable.rb",
29
+ "lib/sluggable_rspec_helper.rb",
30
+ "lib/version.rb",
31
+ "sequel_sluggable.gemspec",
32
+ "spec/sequel_sluggable_spec.rb",
33
+ "spec/spec.opts",
34
+ "spec/spec_helper.rb"
35
+ ]
36
+ s.homepage = %q{http://github.com/pk/sequel_sluggable}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.5}
40
+ s.summary = %q{Sequel plugin which provides Slug functionality for model.}
41
+ s.test_files = [
42
+ "spec/sequel_sluggable_spec.rb",
43
+ "spec/spec_helper.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<sequel>, [">= 0"])
52
+ s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
53
+ s.add_development_dependency(%q<rspec>, [">= 0"])
54
+ s.add_development_dependency(%q<yard>, [">= 0"])
55
+ else
56
+ s.add_dependency(%q<sequel>, [">= 0"])
57
+ s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
58
+ s.add_dependency(%q<rspec>, [">= 0"])
59
+ s.add_dependency(%q<yard>, [">= 0"])
60
+ end
61
+ else
62
+ s.add_dependency(%q<sequel>, [">= 0"])
63
+ s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
64
+ s.add_dependency(%q<rspec>, [">= 0"])
65
+ s.add_dependency(%q<yard>, [">= 0"])
66
+ end
67
+ end
68
+
@@ -0,0 +1,127 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class Item < Sequel::Model; end
4
+
5
+ describe "SequelSluggable" do
6
+ before(:each) do
7
+ Item.plugin :sluggable,
8
+ :source => :name,
9
+ :target => :slug
10
+ end
11
+
12
+ it "should be loaded using Model.plugin" do
13
+ Item.plugins.should include(Sequel::Plugins::Sluggable)
14
+ end
15
+
16
+ it "should add find_by_pk_or_slug" do
17
+ Item.should respond_to(:find_by_pk_or_slug)
18
+ end
19
+
20
+ it "should add find_by_slug" do
21
+ Item.should respond_to(:find_by_slug)
22
+ end
23
+
24
+ it "should generate slug when saved" do
25
+ Item.create(:name => 'Pavel Kunc').slug.should eql 'pavel-kunc'
26
+ end
27
+
28
+ describe "options handling" do
29
+ before(:each) do
30
+ @sluggator = Proc.new {|value, model| value.chomp.downcase}
31
+ class Item < Sequel::Model; end
32
+ Item.plugin :sluggable,
33
+ :source => :name,
34
+ :target => :slug,
35
+ :sluggator => @sluggator
36
+ end
37
+
38
+ it "should accept source option" do
39
+ Item.sluggable_options[:source].should eql :name
40
+ end
41
+
42
+ it "should accept target option" do
43
+ Item.sluggable_options[:target].should eql :slug
44
+ end
45
+
46
+ it "should accept sluggator option" do
47
+ Item.sluggable_options[:sluggator].should eql @sluggator
48
+ end
49
+
50
+ it "should require source option" do
51
+ class Item < Sequel::Model; end
52
+ lambda { Item.plugin :sluggable }.should raise_error(ArgumentError, "You must provide :source column")
53
+ end
54
+
55
+ it "should default target option to :slug when not provided" do
56
+ class Item < Sequel::Model; end
57
+ Item.plugin :sluggable, :source => :name
58
+ Item.sluggable_options[:target].should eql :slug
59
+ end
60
+
61
+ it "should require sluggator to be Symbol or callable" do
62
+ class Item < Sequel::Model; end
63
+ lambda { Item.plugin :sluggable, :source => :name, :sluggator => 'xy' }.should raise_error(ArgumentError, "If you provide :sluggator it must be Symbol or callable.")
64
+ end
65
+ end
66
+
67
+ describe "::find_by_pk_or_slug" do
68
+ it "should find model by slug" do
69
+ item = Item.create(:name => 'Pavel Kunc')
70
+ Item.find_by_pk_or_slug('pavel-kunc').should eql item
71
+ end
72
+
73
+ it "should find model by id" do
74
+ item = Item.create(:name => 'Pavel Kunc')
75
+ Item.find_by_pk_or_slug(item.id).should eql item
76
+ end
77
+
78
+ it "should return nil if model not found and searching by slug" do
79
+ item = Item.create(:name => 'Pavel Kunc')
80
+ Item.find_by_pk_or_slug('tonda-kunc').should be_nil
81
+ end
82
+
83
+ it "should return nil if model not found and searching by id" do
84
+ item = Item.create(:name => 'Pavel Kunc')
85
+ Item.find_by_pk_or_slug(1000).should be_nil
86
+ end
87
+ end
88
+
89
+ describe "::find_by_slug" do
90
+ it "should find model by slug" do
91
+ item = Item.create(:name => 'Pavel Kunc')
92
+ Item.find_by_slug('pavel-kunc').should eql item
93
+ end
94
+
95
+ it "should return nil if model not found" do
96
+ item = Item.create(:name => 'Pavel Kunc')
97
+ Item.find_by_slug('tonda-kunc').should be_nil
98
+ end
99
+ end
100
+
101
+ describe "slug algorithm customization" do
102
+ before(:each) do
103
+ class Item < Sequel::Model; end
104
+ end
105
+
106
+ it "should use to_slug method on model if available" do
107
+ Item.plugin :sluggable,
108
+ :source => :name,
109
+ :target => :slug
110
+ Item.class_eval do
111
+ def to_slug(v)
112
+ v.chomp.downcase.gsub(/[^a-z0-9]+/,'_')
113
+ end
114
+ end
115
+ Item.create(:name => 'Pavel Kunc').slug.should eql 'pavel_kunc'
116
+ end
117
+
118
+ it "should use only :sluggator proc if defined" do
119
+ Item.plugin :sluggable,
120
+ :source => :name,
121
+ :target => :slug,
122
+ :sluggator => Proc.new {|value, model| value.chomp.downcase.gsub(/[^a-z0-9]+/,'_')}
123
+ Item.create(:name => 'Pavel Kunc').slug.should eql 'pavel_kunc'
124
+ end
125
+ end
126
+
127
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,20 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'sequel'
4
+ require 'sequel_sluggable'
5
+ require 'spec'
6
+ require 'spec/autorun'
7
+
8
+ # Create model to test on
9
+ DB = Sequel.sqlite
10
+ DB.create_table :items do
11
+ primary_key :id
12
+ String :name
13
+ String :slug
14
+ end
15
+
16
+ class Item < Sequel::Model; end
17
+
18
+ Spec::Runner.configure do |config|
19
+ config.after(:each) { Item.delete }
20
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sequel_sluggable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Pavel Kunc
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-14 00:00:00 +00:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: sequel
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: sqlite3-ruby
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: yard
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ description: Sequel plugin which provides Slug functionality for model.
56
+ email: pavel.kunc@gmail.com
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files:
62
+ - LICENSE
63
+ - README.rdoc
64
+ - TODO
65
+ files:
66
+ - .document
67
+ - .gitignore
68
+ - LICENSE
69
+ - README.rdoc
70
+ - Rakefile
71
+ - TODO
72
+ - VERSION
73
+ - lib/sequel_sluggable.rb
74
+ - lib/sluggable_rspec_helper.rb
75
+ - lib/version.rb
76
+ - sequel_sluggable.gemspec
77
+ - spec/sequel_sluggable_spec.rb
78
+ - spec/spec.opts
79
+ - spec/spec_helper.rb
80
+ has_rdoc: true
81
+ homepage: http://github.com/pk/sequel_sluggable
82
+ licenses: []
83
+
84
+ post_install_message:
85
+ rdoc_options:
86
+ - --charset=UTF-8
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: "0"
94
+ version:
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: "0"
100
+ version:
101
+ requirements: []
102
+
103
+ rubyforge_project:
104
+ rubygems_version: 1.3.5
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: Sequel plugin which provides Slug functionality for model.
108
+ test_files:
109
+ - spec/sequel_sluggable_spec.rb
110
+ - spec/spec_helper.rb