louisville 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.ruby-vesion +0 -0
  7. data/.travis.yml +42 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +124 -0
  11. data/Rakefile +9 -0
  12. data/gemfiles/ar30.gemfile +13 -0
  13. data/gemfiles/ar31.gemfile +12 -0
  14. data/gemfiles/ar32.gemfile +12 -0
  15. data/gemfiles/ar40.gemfile +12 -0
  16. data/gemfiles/ar41.gemfile +12 -0
  17. data/gemfiles/ar42.gemfile +12 -0
  18. data/lib/louisville/collision_resolvers/abstract.rb +101 -0
  19. data/lib/louisville/collision_resolvers/none.rb +11 -0
  20. data/lib/louisville/collision_resolvers/numeric_sequence.rb +78 -0
  21. data/lib/louisville/collision_resolvers/string_sequence.rb +48 -0
  22. data/lib/louisville/config.rb +60 -0
  23. data/lib/louisville/extensions/collision.rb +87 -0
  24. data/lib/louisville/extensions/finder.rb +109 -0
  25. data/lib/louisville/extensions/history.rb +59 -0
  26. data/lib/louisville/extensions/setter.rb +44 -0
  27. data/lib/louisville/slug.rb +8 -0
  28. data/lib/louisville/slugger.rb +103 -0
  29. data/lib/louisville/util.rb +39 -0
  30. data/lib/louisville/version.rb +13 -0
  31. data/lib/louisville.rb +28 -0
  32. data/louisville.gemspec +21 -0
  33. data/spec/collision_spec.rb +84 -0
  34. data/spec/column_spec.rb +40 -0
  35. data/spec/finder_spec.rb +70 -0
  36. data/spec/history_spec.rb +96 -0
  37. data/spec/numeric_sequence_spec.rb +36 -0
  38. data/spec/setter_spec.rb +42 -0
  39. data/spec/slugger_spec.rb +89 -0
  40. data/spec/spec_helper.rb +35 -0
  41. data/spec/string_sequence_spec.rb +41 -0
  42. data/spec/support/database.example.yml +6 -0
  43. data/spec/support/database.yml +6 -0
  44. data/spec/support/schema.rb +20 -0
  45. metadata +112 -0
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe Louisville::Extensions::Finder do
4
+
5
+ class FinderUser < ActiveRecord::Base
6
+ self.table_name = :users
7
+
8
+ include Louisville::Slugger
9
+
10
+ slug :name, :finder => true
11
+ end
12
+
13
+ class FindeerUser < FinderUser
14
+
15
+ end
16
+
17
+ class FinderHistoryUser < ActiveRecord::Base
18
+ self.table_name = :users
19
+ include Louisville::Slugger
20
+
21
+ slug :name, :finder => true, :history => true
22
+ end
23
+
24
+
25
+ it 'should allow a model to be found via its slug' do
26
+ f = FinderUser.new
27
+ f.name = 'harold'
28
+ expect(f.save).to eq(true)
29
+
30
+ expect(FinderUser.find('harold')).to eq(f)
31
+ end
32
+
33
+ it 'should blow up when nothing can be found' do
34
+ expect{
35
+ FinderUser.find('dajlsflj290rjodsals')
36
+ }.to raise_error(ActiveRecord::RecordNotFound)
37
+ end
38
+
39
+ it 'should be fine with inhertance' do
40
+ f = FindeerUser.new
41
+ f.name = 'harmon'
42
+ expect(f.save).to eq(true)
43
+
44
+ expect(FindeerUser.find('harmon')).to eq(f)
45
+ end
46
+
47
+ it 'should raise an error with history enabled' do
48
+ f = FinderHistoryUser.new
49
+ f.name = 'happ'
50
+ expect(f.save).to eq(true)
51
+
52
+ f.reload
53
+ f.name = 'happy'
54
+ expect(f.save).to eq(true)
55
+
56
+ expect(f.slug).to eq('happy')
57
+ expect(
58
+ Louisville::Slug.where(:sluggable_type => 'FinderHistoryUser', :sluggable_id => f.id).count
59
+ ).to eq(1)
60
+
61
+ expect(FinderHistoryUser.find('happ')).to eq(f)
62
+ expect(FinderHistoryUser.find('happy')).to eq(f)
63
+
64
+ expect{
65
+ FinderHistoryUser.find('harvey')
66
+ }.to raise_error(ActiveRecord::RecordNotFound)
67
+ end
68
+
69
+
70
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ describe Louisville::Extensions::History do
4
+
5
+ class MinimalHistoryUser < ActiveRecord::Base
6
+ self.table_name = :users
7
+
8
+ include Louisville::Slugger
9
+
10
+ slug :name, :history => true
11
+ end
12
+
13
+ it 'should validate that the slug is present' do
14
+ u = MinimalHistoryUser.new
15
+ expect(u.save).to eq(false)
16
+
17
+ expect(u.errors[:slug].to_s).to match(/be blank/)
18
+ end
19
+
20
+ it 'should push the previous slug into the history if it changes' do
21
+ u = MinimalHistoryUser.new
22
+ u.name = 'joe'
23
+
24
+ expect{
25
+ expect(u.save).to eq(true)
26
+ }.not_to change(Louisville::Slug, :count)
27
+
28
+ u.name = 'joey'
29
+ expect{
30
+ expect(u.save).to eq(true)
31
+ }.to change(Louisville::Slug, :count).by(1)
32
+
33
+ expect(u.slug).to eq('joey')
34
+ history = Louisville::Slug.last
35
+
36
+ expect(history.sluggable_type).to eq('MinimalHistoryUser')
37
+ expect(history.sluggable_id).to eq(u.id)
38
+
39
+ expect(history.slug_base).to eq('joe')
40
+ expect(history.slug_sequence).to eq(1)
41
+ end
42
+
43
+ it 'should delete the slug from the history if it is reassigned' do
44
+ u = MinimalHistoryUser.new
45
+ u.name = 'phil'
46
+ expect(u.save).to eq(true)
47
+
48
+ u.name = 'philip'
49
+ expect(u.save).to eq(true)
50
+
51
+ expect(u.slug).to eq('philip')
52
+
53
+ history = Louisville::Slug.last
54
+
55
+ expect(history.sluggable_type).to eq(u.class.name)
56
+ expect(history.sluggable_id).to eq(u.id)
57
+
58
+ u.name = 'phil'
59
+ expect(u.save).to eq(true)
60
+
61
+ history2 = Louisville::Slug.last
62
+
63
+ expect(Louisville::Slug.where(:id => history.id).count).to eq(0)
64
+ expect(history2.slug_base).to eq('philip')
65
+ end
66
+
67
+ it 'should provide a way to find a user via the slug' do
68
+ u = MinimalHistoryUser.new
69
+ u.name = 'james'
70
+ expect(u.save).to eq(true)
71
+
72
+ expect(MinimalHistoryUser.find('james')).to eq(u)
73
+
74
+ u.name = 'jams'
75
+ expect(u.save).to eq(true)
76
+
77
+ expect(MinimalHistoryUser.find('jams')).to eq(u)
78
+ expect(MinimalHistoryUser.find('james')).to eq(u)
79
+
80
+ end
81
+
82
+ it 'should destroy the slugs when a record is destroyed' do
83
+ u = MinimalHistoryUser.new
84
+ u.name = 'jackford'
85
+ expect(u.save).to eq(true)
86
+
87
+ u.name = 'jackson'
88
+ expect{
89
+ expect(u.save).to eq(true)
90
+ }.to change(Louisville::Slug, :count).by(1)
91
+
92
+ expect{
93
+ u.destroy
94
+ }.to change(Louisville::Slug, :count).by(-1)
95
+ end
96
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Louisville::CollisionResolvers::NumericSequence do
4
+
5
+ class NsUser < ActiveRecord::Base
6
+ self.table_name = :users
7
+
8
+ include Louisville::Slugger
9
+
10
+ slug :name, :collision => :numeric_sequence
11
+ end
12
+
13
+ it 'should solve collisions by incrementing the sequence column' do
14
+ a = NsUser.new
15
+ a.name = 'chris'
16
+ expect(a.save).to eq(true)
17
+
18
+ expect(a.slug).to eq('chris')
19
+ expect(a.slug_sequence).to eq(1)
20
+
21
+ b = NsUser.new
22
+ b.name = 'chris'
23
+ expect(b.save).to eq(true)
24
+
25
+ expect(b.slug).to eq('chris')
26
+ expect(b.slug_sequence).to eq(2)
27
+
28
+ c = NsUser.new
29
+ c.name = 'chris'
30
+ expect(c.save).to eq(true)
31
+
32
+ expect(c.slug).to eq('chris')
33
+ expect(c.slug_sequence).to eq(3)
34
+ end
35
+
36
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Louisville::Extensions::Setter do
4
+
5
+ class SetterUser < ActiveRecord::Base
6
+ self.table_name = :users
7
+
8
+ include Louisville::Slugger
9
+
10
+ slug :name, :setter => true, :collision => :string_sequence
11
+
12
+ end
13
+
14
+ it 'should provide setters for the desired slug' do
15
+
16
+ u = SetterUser.new
17
+ u.name = 'carl'
18
+ u.desired_slug = 'carljr'
19
+
20
+ expect(u.save).to eq(true)
21
+
22
+ expect(u.slug).to eq('carljr')
23
+
24
+ end
25
+
26
+ it 'should not attempt to uniquify if the desired slug is provided' do
27
+
28
+ u = SetterUser.new
29
+ u.name = 'carey'
30
+ expect(u.save).to eq(true)
31
+
32
+ u2 = SetterUser.new
33
+ u2.name = 'kerry'
34
+ u2.desired_slug = 'carey'
35
+
36
+ expect(u2.save).to eq(false)
37
+
38
+ expect(u2.errors[:slug].to_s).to match(/has already been taken/)
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ describe Louisville::Slugger do
4
+
5
+ class MinimalUser < ActiveRecord::Base
6
+ self.table_name = :users
7
+
8
+ include Louisville::Slugger
9
+
10
+ slug :name
11
+ end
12
+
13
+ let(:config){ MinimalUser.louisville_config }
14
+
15
+ it 'should assume the appropriate defaults' do
16
+ expect(config[:field]).to eq(:name)
17
+ expect(config[:column]).to eq(:slug)
18
+ expect(config[:collision]).to eq(:none)
19
+ expect(config[:finder]).to eq(true)
20
+ expect(config[:history]).to eq(false)
21
+ end
22
+
23
+ it 'should wrap the field with louisville accessors' do
24
+ u = MinimalUser.new
25
+ u.send(:louisville_slug=, 'test')
26
+
27
+ expect(u.slug).to eq('test')
28
+ expect(u.louisville_slug).to eq('test')
29
+ end
30
+
31
+ it 'should validate that the slug is present' do
32
+ u = MinimalUser.new
33
+ expect(u.save).to eq(false)
34
+
35
+ expect(u.errors[:slug].to_s).to match(/be blank/)
36
+ end
37
+
38
+ it 'should validate that the slug is unique by default' do
39
+ u = MinimalUser.new
40
+ u.name = 'john'
41
+ expect(u.save).to eq(true)
42
+
43
+ u2 = MinimalUser.new
44
+ u2.name = 'john'
45
+ expect(u2.save).to eq(false)
46
+
47
+ expect(u2.errors[:slug].to_s).to match(/has already been taken/)
48
+ end
49
+
50
+ it 'should provide a way to find a user via the slug' do
51
+ u = MinimalUser.new
52
+ u.name = 'frank'
53
+ expect(u.save).to eq(true)
54
+
55
+ expect(MinimalUser.find('frank')).to eq(u)
56
+ end
57
+
58
+ it 'should not apply the slug if the field value changes but the slug base does not' do
59
+ u = MinimalUser.new
60
+ u.name = 'spencer'
61
+ expect(u.save).to eq(true)
62
+
63
+ u.name = 'Spencer'
64
+ expect(u).to be_changed
65
+
66
+ expect(u).to receive(:louisville_slug=).never
67
+ expect(u.save).to eq(true)
68
+ end
69
+
70
+ it 'should only validate when the slug changes or the record is not persisted' do
71
+ u = MinimalUser.new
72
+ u.name = 'daniel'
73
+ expect(u.save).to eq(true)
74
+
75
+ u.email = 'd@test.com'
76
+ expect(u.send(:needs_to_validate_louisville_slug?)).to eq(false)
77
+
78
+ u.name = 'danny'
79
+ u.send(:apply_louisville_slug) # this normally happens before validation
80
+ expect(u.send(:needs_to_validate_louisville_slug?)).to eq(true)
81
+
82
+ u2 = MinimalUser.new
83
+ expect(u2.send(:needs_to_validate_louisville_slug?)).to eq(true)
84
+
85
+ expect(u2.save).to eq(false)
86
+ expect(u2.errors[:slug].to_s).to match(/blank/)
87
+ end
88
+
89
+ end
@@ -0,0 +1,35 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ require 'active_record'
9
+ require 'louisville'
10
+
11
+ begin
12
+ require 'byebug'
13
+ rescue LoadError => e
14
+ puts 'running without debugger'
15
+ end
16
+
17
+ RSpec.configure do |config|
18
+ config.treat_symbols_as_metadata_keys_with_true_values = true
19
+ config.run_all_when_everything_filtered = true
20
+ config.filter_run :focus
21
+
22
+ ActiveRecord::Base.establish_connection(YAML.load_file(File.dirname(__FILE__) + '/support/database.yml'))
23
+ load(File.dirname(__FILE__) + '/support/schema.rb')
24
+
25
+
26
+ config.expect_with :rspec do |c|
27
+ c.syntax = :expect
28
+ end
29
+
30
+ # Run specs in random order to surface order dependencies. If you find an
31
+ # order dependency and want to debug it, you can fix the order by providing
32
+ # the seed, which is printed after each run.
33
+ # --seed 1234
34
+ config.order = 'random'
35
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Louisville::CollisionResolvers::StringSequence do
4
+
5
+ class SsUser < ActiveRecord::Base
6
+ self.table_name = :users
7
+
8
+ include Louisville::Slugger
9
+
10
+ slug :name, :collision => :string_sequence
11
+ end
12
+
13
+ it 'should solve collisions by appending the sequence to the slug' do
14
+ a = SsUser.new
15
+ a.name = 'charlie'
16
+ expect(a.save).to eq(true)
17
+
18
+ expect(a.slug).to eq('charlie')
19
+ expect(a.slug_sequence).to eq(1)
20
+
21
+ b = SsUser.new
22
+ b.name = 'charlie'
23
+ expect(b.save).to eq(true)
24
+
25
+ expect(b.slug).to eq('charlie--2')
26
+
27
+ c = SsUser.new
28
+ c.name = 'charlie'
29
+ expect(c.save).to eq(true)
30
+
31
+ expect(c.slug).to eq('charlie--3')
32
+
33
+ # ensures the sql matcher is working correctly
34
+ b.reload
35
+ b.name = 'Charlie'
36
+ b.save
37
+
38
+ expect(b.slug).to eq('charlie--2')
39
+ end
40
+
41
+ end
@@ -0,0 +1,6 @@
1
+ adapter: 'mysql2'
2
+ host: localhost
3
+ database: louisville_test
4
+ encoding: utf8
5
+ username: root
6
+ password:
@@ -0,0 +1,6 @@
1
+ adapter: 'mysql2'
2
+ host: localhost
3
+ database: louisville_test
4
+ encoding: utf8
5
+ username: root
6
+ password:
@@ -0,0 +1,20 @@
1
+ ActiveRecord::Schema.define(:version => 20130628161227) do
2
+
3
+ create_table "users", :force => true do |t|
4
+ t.string "name"
5
+ t.string "email"
6
+ t.string "slug"
7
+ t.integer "slug_sequence", :default => 1
8
+ t.string "other_slug"
9
+ t.integer "other_slug_sequence", :default => 1
10
+ t.datetime "created_at", :null => false
11
+ t.datetime "updated_at", :null => false
12
+ end
13
+
14
+ create_table "slugs", :force => true do |t|
15
+ t.string "sluggable_type"
16
+ t.integer "sluggable_id"
17
+ t.string "slug_base"
18
+ t.integer "slug_sequence", :default => 1
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: louisville
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Mike Nelson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ description: A simple and extensible slugging library for ActiveRecord.
28
+ email:
29
+ - mike@mnelson.io
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - ".rspec"
36
+ - ".ruby-gemset"
37
+ - ".ruby-version"
38
+ - ".ruby-vesion"
39
+ - ".travis.yml"
40
+ - Gemfile
41
+ - LICENSE.txt
42
+ - README.md
43
+ - Rakefile
44
+ - gemfiles/ar30.gemfile
45
+ - gemfiles/ar31.gemfile
46
+ - gemfiles/ar32.gemfile
47
+ - gemfiles/ar40.gemfile
48
+ - gemfiles/ar41.gemfile
49
+ - gemfiles/ar42.gemfile
50
+ - lib/louisville.rb
51
+ - lib/louisville/collision_resolvers/abstract.rb
52
+ - lib/louisville/collision_resolvers/none.rb
53
+ - lib/louisville/collision_resolvers/numeric_sequence.rb
54
+ - lib/louisville/collision_resolvers/string_sequence.rb
55
+ - lib/louisville/config.rb
56
+ - lib/louisville/extensions/collision.rb
57
+ - lib/louisville/extensions/finder.rb
58
+ - lib/louisville/extensions/history.rb
59
+ - lib/louisville/extensions/setter.rb
60
+ - lib/louisville/slug.rb
61
+ - lib/louisville/slugger.rb
62
+ - lib/louisville/util.rb
63
+ - lib/louisville/version.rb
64
+ - louisville.gemspec
65
+ - spec/collision_spec.rb
66
+ - spec/column_spec.rb
67
+ - spec/finder_spec.rb
68
+ - spec/history_spec.rb
69
+ - spec/numeric_sequence_spec.rb
70
+ - spec/setter_spec.rb
71
+ - spec/slugger_spec.rb
72
+ - spec/spec_helper.rb
73
+ - spec/string_sequence_spec.rb
74
+ - spec/support/database.example.yml
75
+ - spec/support/database.yml
76
+ - spec/support/schema.rb
77
+ homepage: http://github.com/mnelson/louisville
78
+ licenses: []
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.4.6
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Simple and Extensible Slugging
100
+ test_files:
101
+ - spec/collision_spec.rb
102
+ - spec/column_spec.rb
103
+ - spec/finder_spec.rb
104
+ - spec/history_spec.rb
105
+ - spec/numeric_sequence_spec.rb
106
+ - spec/setter_spec.rb
107
+ - spec/slugger_spec.rb
108
+ - spec/spec_helper.rb
109
+ - spec/string_sequence_spec.rb
110
+ - spec/support/database.example.yml
111
+ - spec/support/database.yml
112
+ - spec/support/schema.rb