url_keyed_object 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
@@ -11,7 +11,7 @@ Feature: Using for things which are URL key-like
11
11
  """
12
12
  Then @value should match /^[a-z0-9]{5}$/
13
13
 
14
- Scenario: Generating and validating a URL key value
14
+ Scenario: Generating and validating a URL key value as part of object initialisation
15
15
  Given this class:
16
16
  """
17
17
  class HasOpaqueId
@@ -42,3 +42,17 @@ Feature: Using for things which are URL key-like
42
42
  @object_with_id = HasOpaqueId.new
43
43
  """
44
44
  Then @object_with_id.id should match /^[a-z0-9]{5}$/
45
+
46
+ Scenario: Generating a URL key value of arbitrary length
47
+ When I make a call to generate a URL key:
48
+ """
49
+ @value = UrlKeyedObject.generate_unchecked_url_key(18)
50
+ """
51
+ Then @value should match /^[a-z0-9]{18}$/
52
+
53
+ Scenario: Generating and validating a URL key value of arbitrary length
54
+ When I make a call to generate a valid URL key (with an admittedly nonsensical validation block):
55
+ """
56
+ @value = UrlKeyedObject.generate_checked_url_key(18) { |value| value.length == 18 }
57
+ """
58
+ Then @value should match /^[a-z0-9]{18}$/
@@ -20,7 +20,7 @@ Feature: Using with ActiveRecord
20
20
  And this class:
21
21
  """
22
22
  class Thing < ActiveRecord::Base
23
- include UrlKeyedObject::ActiveRecord
23
+ acts_as_url_keyed
24
24
  end
25
25
  """
26
26
 
@@ -48,7 +48,7 @@ Feature: Using with ActiveRecord
48
48
  And a warning should have been logged
49
49
 
50
50
  Scenario: Attempting to set url_key ought to fail
51
- When I make an instance using mass-assignment:
51
+ When I make an instance and set the value of url_key manually:
52
52
  """
53
53
  @instance = Thing.new
54
54
  @instance.url_key = 'abcde'
@@ -0,0 +1,58 @@
1
+ @db
2
+ Feature: More advanced usage with ActiveRecord
3
+ In order to generate and validate non-standard URL keys in an ActiveRecord::Base object
4
+ A Rails developer
5
+ Wants to include and use UrlKeyedObject
6
+
7
+ # The default case is for a 5-character ID, stored in the url_key column.
8
+ # Here we have an existing column we want to re-use, and we want a longer URL key
9
+ #
10
+ # calling acts_as_url_keyed and setting a couple of options is all that's needed.
11
+ Background:
12
+ Given a database, with this table defined:
13
+ """
14
+ create_table :advanced_things do |t|
15
+ t.string :opaque_id, :null => false
16
+
17
+ t.timestamps
18
+ end
19
+ """
20
+ And this class:
21
+ """
22
+ class AdvancedThing < ActiveRecord::Base
23
+ acts_as_url_keyed :url_key_column => :opaque_id, :url_key_length => 8
24
+ end
25
+ """
26
+
27
+ Scenario: An unsaved model object with UrlKeyedObject included
28
+ When I make a bare instance:
29
+ """
30
+ @instance = AdvancedThing.new
31
+ """
32
+ Then @instance.opaque_id should be nil
33
+
34
+ Scenario: A saved model object with an 8-character URL key on #opaque_id
35
+ When I make and save an instance:
36
+ """
37
+ @instance = AdvancedThing.new
38
+ @instance.save!
39
+ """
40
+ Then @instance.opaque_id should match /^[a-z0-9]{8}$/
41
+
42
+ Scenario: Attempting to mass-assign opaque_id ought to fail
43
+ When I make an instance using mass-assignment:
44
+ """
45
+ @instance = AdvancedThing.new(:opaque_id => 'abcde')
46
+ """
47
+ Then @instance.opaque_id should be nil
48
+ And a warning should have been logged
49
+
50
+ Scenario: Attempting to set opaque_id ought to fail
51
+ When I make an instance and set the value of opaque_id manually:
52
+ """
53
+ @instance = AdvancedThing.new
54
+ @instance.opaque_id = 'abcde'
55
+ """
56
+ Then @instance.opaque_id should be nil
57
+ And a warning should have been logged
58
+
@@ -1,40 +1,67 @@
1
1
  require 'url_keyed_object'
2
+ require 'active_record'
2
3
 
3
4
  module UrlKeyedObject
4
5
  module ActiveRecord
5
- # --
6
- # the stuff that actually gets included.
7
- # comment included for my benefit, in case I forget (quite likely)
8
- # ++
6
+ # def url_key=(value)
7
+ # logger.warn('Attempt to set #url_key!')
8
+ # nil
9
+ # end
9
10
 
10
- def to_param
11
- url_key
12
- end
13
-
14
- def url_key=(value)
15
- logger.warn('Attempt to set #url_key!')
16
- nil
17
- end
18
-
19
- # --
20
- # Validations
21
- # ++
22
11
 
23
- def self.included(model)
24
- model.class_eval do
12
+ module ClassMethods
13
+ def url_key_column
14
+ @url_key_column ||= :url_key
15
+ end
16
+
17
+ def url_key_length
18
+ @url_key_length ||= 5
19
+ end
20
+
21
+ def acts_as_url_keyed(opts = {})
22
+ attr_writer :url_key_length
23
+
24
+ @url_key_column = opts[:url_key_column] if opts.has_key?(:url_key_column)
25
+ @url_key_length = opts[:url_key_length] if opts.has_key?(:url_key_length)
26
+
25
27
  before_create :generate_valid_url_key
28
+
29
+ include InstanceMethods
30
+
31
+ define_method("#{url_key_column}=") { |value| logger.warn("Attempt to set ##{url_key_column}!"); nil }
26
32
  end
27
33
  end
28
34
 
29
- protected
30
-
31
- def generate_valid_url_key
32
- new_url_key = UrlKeyedObject.generate_checked_url_key { |value| self.valid_url_key?(value) }
33
- write_attribute(:url_key, new_url_key)
35
+ module InstanceMethods
36
+ protected
37
+
38
+ def generate_valid_url_key
39
+ new_url_key = UrlKeyedObject.generate_checked_url_key(url_key_length) { |value| self.valid_url_key?(value) }
40
+ write_attribute(url_key_column, new_url_key)
41
+ end
42
+
43
+ def valid_url_key?(url_key)
44
+ self.class.send("find_by_#{url_key_column}", url_key).nil?
45
+ end
46
+
47
+ def url_key_column
48
+ self.class.url_key_column
49
+ end
50
+
51
+ def url_key_length
52
+ self.class.url_key_length
53
+ end
54
+
55
+
56
+ def to_param
57
+ send url_key_column
58
+ end
34
59
  end
35
60
 
36
- def valid_url_key?(url_key)
37
- self.class.find_by_url_key(url_key).nil?
61
+ def self.included(model_class)
62
+ model_class.extend ClassMethods
38
63
  end
39
64
  end
40
- end
65
+ end
66
+
67
+ ActiveRecord::Base.send :include, UrlKeyedObject::ActiveRecord
@@ -13,24 +13,24 @@ module UrlKeyedObject
13
13
  end
14
14
 
15
15
  # generates a url key from a random 5-digit base 31 number, without checking its uniqueness
16
- def generate_unchecked_url_key
17
- (1..5).collect do
16
+ def generate_unchecked_url_key(length = 5)
17
+ (1..length).collect do
18
18
  key_encoding[rand(31)]
19
19
  end.join('')
20
20
  end
21
21
 
22
22
  # Keeps generating new URL keys until the passed-in block returns true
23
- def generate_checked_url_key
24
- key = generate_unchecked_url_key
23
+ def generate_checked_url_key(length = 5)
24
+ key = generate_unchecked_url_key(length)
25
25
  while !yield(key)
26
- key = generate_unchecked_url_key
26
+ key = generate_unchecked_url_key(length)
27
27
  end
28
28
  key
29
29
  end
30
30
 
31
31
  # Validate the well-formedness of a URL key
32
- def well_formed_url_key?(url_key)
33
- !url_key.match(/^[0-9abcdefghjkmnpqrsvwxyz]{5}$/).nil?
32
+ def well_formed_url_key?(url_key, length = 5)
33
+ !url_key.match(Regexp.new("^[0-9abcdefghjkmnpqrsvwxyz]{#{length.to_i}}$")).nil?
34
34
  end
35
35
 
36
36
  # decode a moderately dirty URL key
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  $:.unshift(File.dirname(__FILE__))
2
2
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rubygems'
4
+ gem 'activerecord'
3
5
  require 'url_keyed_object'
4
6
  require 'url_keyed_object/active_record'
5
7
  require 'spec'
6
8
  require 'spec/autorun'
7
- require 'rubygems'
8
- gem 'activerecord'
9
9
 
10
10
  Spec::Runner.configure do |config|
11
11
  config.mock_with :mocha
@@ -37,7 +37,7 @@ describe UrlKeyedObject::ActiveRecord do
37
37
  'UrlKeyedObjectMock'
38
38
  end
39
39
 
40
- include UrlKeyedObject::ActiveRecord
40
+ acts_as_url_keyed
41
41
  end
42
42
 
43
43
  ActiveRecord::Base.logger = Logger.new(STDERR)
@@ -5,6 +5,10 @@ describe UrlKeyedObject do
5
5
  UrlKeyedObject.generate_unchecked_url_key.should match(/[0-9abcdefghjkmnpqrsvwxyz]{5}/)
6
6
  end
7
7
 
8
+ it "should be able to generate an arbitrary-length URL key" do
9
+ UrlKeyedObject.generate_unchecked_url_key(7).should match(/[0-9abcdefghjkmnpqrsvwxyz]{7}/)
10
+ end
11
+
8
12
  describe "decoding a moderately dirty URL key (case insensitivity, ambiguous character replacement)" do
9
13
  it "should be able to cope with O o 0 ambiguity" do
10
14
  UrlKeyedObject.decode_url_key('Oo0ab').should == '000ab'
@@ -37,17 +41,27 @@ describe UrlKeyedObject do
37
41
  UrlKeyedObject.well_formed_url_key?(malformed_url_key).should be_false
38
42
  end
39
43
  end
44
+
45
+ it "should be able to cope with a different specified length" do
46
+ UrlKeyedObject.well_formed_url_key?('abcdef', 6).should be_true
47
+ end
40
48
  end
41
49
 
42
50
  describe "validity of URL keys" do
43
51
  it "should be able to evaluate a block to check key validity, repeating until it generates one" do
44
52
  valid_key_sequence = sequence('valid key sequence')
45
- UrlKeyedObject.expects(:generate_unchecked_url_key).in_sequence(valid_key_sequence).returns('a1url')
46
- UrlKeyedObject.expects(:generate_unchecked_url_key).in_sequence(valid_key_sequence).returns('a2url')
53
+ UrlKeyedObject.expects(:generate_unchecked_url_key).with(5).returns('a1url').
54
+ in_sequence(valid_key_sequence)
55
+ UrlKeyedObject.expects(:generate_unchecked_url_key).with(5).returns('a2url').
56
+ in_sequence(valid_key_sequence)
47
57
 
48
58
  key = UrlKeyedObject.generate_checked_url_key { |value| value != 'a1url' }
49
59
 
50
60
  key.should == 'a2url'
51
61
  end
62
+
63
+ it "should description" do
64
+
65
+ end
52
66
  end
53
67
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: url_keyed_object
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Patterson
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-19 00:00:00 +00:00
12
+ date: 2010-01-20 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -68,6 +68,7 @@ files:
68
68
  - features/support/hooks.rb
69
69
  - features/support/recording_logger.rb
70
70
  - features/with_active_record-basic.feature
71
+ - features/with_active_record-more-advanced.feature
71
72
  - lib/url_keyed_object.rb
72
73
  - lib/url_keyed_object/active_record.rb
73
74
  - spec/spec.opts