pseudocephalopod 0.3.1 → 0.3.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/Gemfile DELETED
@@ -1,20 +0,0 @@
1
- source :gemcutter
2
-
3
- # Setup gems
4
- gem "activerecord", "= 3.0.0"
5
- gem "reversible_data"
6
- gem "uuid"
7
- gem "sqlite3-ruby", :require => "sqlite3"
8
-
9
- gem "shoulda", :require => nil
10
- gem "redgreen", :require => nil if RUBY_VERSION < "1.9"
11
- gem "rcov", :require => nil
12
- gem "reek", :require => nil
13
- gem "roodi", :require => nil
14
- gem "flay", :require => nil
15
- gem "flog", :require => nil
16
- gem "rake", :require => nil
17
- gem "Saikuro", :require => nil
18
- gem "jeweler", :require => nil
19
-
20
- gem 'ruby-debug', :require => nil
@@ -1,82 +0,0 @@
1
- GEM
2
- remote: http://rubygems.org/
3
- specs:
4
- Saikuro (1.1.0)
5
- activemodel (3.0.0)
6
- activesupport (= 3.0.0)
7
- builder (~> 2.1.2)
8
- i18n (~> 0.4.1)
9
- activerecord (3.0.0)
10
- activemodel (= 3.0.0)
11
- activesupport (= 3.0.0)
12
- arel (~> 1.0.0)
13
- tzinfo (~> 0.3.23)
14
- activesupport (3.0.0)
15
- arel (1.0.1)
16
- activesupport (~> 3.0.0)
17
- builder (2.1.2)
18
- columnize (0.3.1)
19
- flay (1.4.1)
20
- ruby_parser (~> 2.0)
21
- sexp_processor (~> 3.0)
22
- flog (2.5.0)
23
- ruby_parser (~> 2.0)
24
- sexp_processor (~> 3.0)
25
- gemcutter (0.6.1)
26
- git (1.2.5)
27
- i18n (0.4.1)
28
- jeweler (1.4.0)
29
- gemcutter (>= 0.1.0)
30
- git (>= 1.2.5)
31
- rubyforge (>= 2.0.0)
32
- json_pure (1.4.6)
33
- linecache (0.43)
34
- macaddr (1.0.0)
35
- rake (0.8.7)
36
- rcov (0.9.9)
37
- redgreen (1.2.2)
38
- reek (1.2.8)
39
- ruby2ruby (~> 1.2)
40
- ruby_parser (~> 2.0)
41
- sexp_processor (~> 3.0)
42
- reversible_data (0.1.0)
43
- roodi (2.1.0)
44
- ruby_parser
45
- ruby-debug (0.10.3)
46
- columnize (>= 0.1)
47
- ruby-debug-base (~> 0.10.3.0)
48
- ruby-debug-base (0.10.3)
49
- linecache (>= 0.3)
50
- ruby2ruby (1.2.5)
51
- ruby_parser (~> 2.0)
52
- sexp_processor (~> 3.0)
53
- ruby_parser (2.0.5)
54
- sexp_processor (~> 3.0)
55
- rubyforge (2.0.4)
56
- json_pure (>= 1.1.7)
57
- sexp_processor (3.0.5)
58
- shoulda (2.11.3)
59
- sqlite3-ruby (1.3.1)
60
- tzinfo (0.3.23)
61
- uuid (2.3.1)
62
- macaddr (~> 1.0)
63
-
64
- PLATFORMS
65
- ruby
66
-
67
- DEPENDENCIES
68
- Saikuro
69
- activerecord (= 3.0.0)
70
- flay
71
- flog
72
- jeweler
73
- rake
74
- rcov
75
- redgreen
76
- reek
77
- reversible_data
78
- roodi
79
- ruby-debug
80
- shoulda
81
- sqlite3-ruby
82
- uuid
@@ -1,24 +0,0 @@
1
- module Pseudocephalopod
2
- module Generators
3
- class SlugMigrationGenerator < Rails::Generators::NamedBase
4
- include Rails::Generators::Migration
5
-
6
- def self.source_root
7
- @_ps_source_root ||= File.expand_path("templates", File.dirname(__FILE__))
8
- end
9
-
10
- def self.next_migration_number(dirname) #:nodoc:
11
- if ActiveRecord::Base.timestamped_migrations
12
- Time.now.utc.strftime("%Y%m%d%H%M%S")
13
- else
14
- "%.3d" % (current_migration_number(dirname) + 1)
15
- end
16
- end
17
-
18
- def create_migration_file
19
- migration_template "migration.erb", "db/migrate/add_cached_slug_to_#{table_name}.rb"
20
- end
21
-
22
- end
23
- end
24
- end
@@ -1,12 +0,0 @@
1
- class <%= migration_class_name %> < ActiveRecord::Migration
2
-
3
- def self.up
4
- add_column <%= table_name.to_sym.inspect %>, :cached_slug, :string
5
- add_index <%= table_name.to_sym.inspect %>, :cached_slug
6
- end
7
-
8
- def self.down
9
- remove_column <%= table_name.to_sym.inspect %>, :cached_slug
10
- end
11
-
12
- end
@@ -1,24 +0,0 @@
1
- module Pseudocephalopod
2
- module Generators
3
- class SlugsGenerator < Rails::Generators::Base
4
- include Rails::Generators::Migration
5
-
6
- def self.source_root
7
- @_ps_source_root ||= File.expand_path("templates", File.dirname(__FILE__))
8
- end
9
-
10
- def self.next_migration_number(dirname) #:nodoc:
11
- if ActiveRecord::Base.timestamped_migrations
12
- Time.now.utc.strftime("%Y%m%d%H%M%S")
13
- else
14
- "%.3d" % (current_migration_number(dirname) + 1)
15
- end
16
- end
17
-
18
- def create_migration_file
19
- migration_template "migration.erb", "db/migrate/create_pseudocephalopod_slugs.rb"
20
- end
21
-
22
- end
23
- end
24
- end
@@ -1,20 +0,0 @@
1
- class CreatePseudocephalopodSlugs < ActiveRecord::Migration
2
-
3
- def self.up
4
- create_table :slugs do |t|
5
- t.string :scope
6
- t.string :slug
7
- t.integer :record_id
8
- t.datetime :created_at
9
- end
10
- add_index :slugs, [:scope, :slug]
11
- add_index :slugs, [:scope, :record_id]
12
- add_index :slugs, [:scope, :slug, :created_at]
13
- add_index :slugs, [:scope, :record_id, :created_at]
14
- end
15
-
16
- def self.down
17
- drop_table :slugs
18
- end
19
-
20
- end
@@ -1,112 +0,0 @@
1
- module Pseudocephalopod
2
- module ActiveRecordMethods
3
- AR_CLASS_ATTRIBUTE_NAMES = %w(cached_slug_column slug_source slug_convertor_proc default_uuid_slug use_slug_history sync_slugs slug_scope use_slug_cache use_slug_to_param).map(&:to_sym)
4
-
5
- def is_sluggable(source = :name, options = {})
6
- options.symbolize_keys!
7
- class_attribute *AR_CLASS_ATTRIBUTE_NAMES
8
- attr_accessor :found_via_slug
9
- # Load extensions
10
- extend ClassMethods
11
- include InstanceMethods
12
- extend Pseudocephalopod::Scopes
13
- extend Pseudocephalopod::Finders
14
- self.slug_source = source.to_sym
15
- set_slug_options options
16
- alias_method :to_param, :to_slug if use_slug_to_param
17
- include Pseudocephalopod::SlugHistory if use_slug_history
18
- include Pseudocephalopod::Caching if use_slug_cache
19
- before_save :autogenerate_slug
20
- end
21
-
22
- module InstanceMethods
23
-
24
- def to_slug
25
- cached_slug.present? ? cached_slug : id.to_s
26
- end
27
-
28
- def generate_slug
29
- slug_value = send(self.slug_source)
30
- slug_value = self.slug_convertor_proc.call(slug_value) if slug_value.present?
31
- if slug_value.present?
32
- scope = self.class.other_than(self).slug_scope_relation(self)
33
- slug_value = Pseudocephalopod.next_value(scope, slug_value)
34
- write_attribute self.cached_slug_column, slug_value
35
- elsif self.default_uuid_slug
36
- write_attribute self.cached_slug_column, Pseudocephalopod.generate_uuid_slug
37
- else
38
- write_attribute self.cached_slug_column, nil
39
- end
40
- end
41
-
42
- def generate_slug!
43
- generate_slug
44
- save :validate => false
45
- end
46
-
47
- def autogenerate_slug
48
- generate_slug if should_generate_slug?
49
- end
50
-
51
- def should_generate_slug?
52
- send(self.cached_slug_column).blank? || (self.sync_slugs && send(:"#{self.slug_source}_changed?"))
53
- end
54
-
55
- def has_better_slug?
56
- found_via_slug.present? && found_via_slug != to_slug
57
- end
58
-
59
- def slug_scope_key(nested_scope = [])
60
- self.class.slug_scope_key(nested_scope)
61
- end
62
-
63
- end
64
-
65
- module ClassMethods
66
-
67
- def update_all_slugs!
68
- find_each { |r| r.generate_slug! }
69
- end
70
-
71
- def slug_scope_key(nested_scope = [])
72
- ([table_name, slug_scope] + Array(nested_scope)).flatten.compact.join("|")
73
- end
74
-
75
- def slug_scope_relation(record)
76
- has_slug_scope? ? where(slug_scope => record.send(slug_scope)) : scoped
77
- end
78
-
79
- protected
80
-
81
- def has_slug_scope?
82
- self.slug_scope.present?
83
- end
84
-
85
- def set_slug_options(options)
86
- set_slug_convertor options[:convertor]
87
- self.cached_slug_column = (options[:slug_column] || :cached_slug).to_sym
88
- self.slug_scope = options[:scope]
89
- self.default_uuid_slug = !!options.fetch(:uuid, true)
90
- self.sync_slugs = !!options.fetch(:sync, true)
91
- self.use_slug_cache = !!options.fetch(:use_cache, true)
92
- self.use_slug_to_param = !!options.fetch(:to_param, true)
93
- self.use_slug_history = !!options.fetch(:history, Pseudocephalopod::Slug.usable?)
94
- end
95
-
96
- def set_slug_convertor(convertor)
97
- if convertor.present?
98
- unless convertor.respond_to?(:call)
99
- convertor_key = convertor.to_sym
100
- convertor = proc { |r| r.try(convertor_key) }
101
- end
102
- self.slug_convertor_proc = convertor
103
- else
104
- self.slug_convertor_proc = proc do |slug|
105
- slug.respond_to?(:to_url) ? slug.to_url : ActiveSupport::Multibyte::Chars.new(slug.to_s).parameterize
106
- end
107
- end
108
- end
109
-
110
- end
111
- end
112
- end
@@ -1,87 +0,0 @@
1
- require 'digest/sha2'
2
-
3
- module Pseudocephalopod
4
- # Mixin for adding simple caching support to models using pseudocephalod.
5
- # Usually included by passing the :cache option as true (by default it is
6
- # true, you can disable by passing :cache as false or nil).
7
- module Caching
8
- extend ActiveSupport::Concern
9
-
10
- mattr_accessor :cache_expires_in
11
- # Cache for 10 minutes by default.
12
- self.cache_expires_in = 600
13
-
14
- included do
15
- after_save :globally_cache_slug
16
- end
17
-
18
- module InstanceMethods
19
- # Automatically called in after_save, will cache this records id
20
- # with to match the current records slug / scope
21
- def globally_cache_slug
22
- return unless send(:"#{self.cached_slug_column}_changed?")
23
- value = self.to_slug
24
- self.class.cache_slug_lookup!(value, self) if value.present?
25
- unless use_slug_history
26
- value = send(:"#{self.cached_slug_column}_was")
27
- self.class.cache_slug_lookup!(value, nil)
28
- end
29
- end
30
-
31
- # Wraps remove_slug_history! to remove each of the slugs
32
- # recording in this models slug history.
33
- def remove_slug_history!
34
- previous_slugs.each { |s| self.class.cache_slug_lookup!(s, nil) }
35
- super
36
- end
37
-
38
- end
39
-
40
- module ClassMethods
41
-
42
- # Wraps find_using_slug to look in the cache.
43
- def find_using_slug(slug, options = {})
44
- # First, attempt to load an id and then record from the cache.
45
- if (cached_id = lookup_cached_id_from_slug(slug)).present?
46
- return find(cached_id, options).tap { |r| r.found_via_slug = slug }
47
- end
48
- # Otherwise, fallback to the normal approach.
49
- super.tap do |record|
50
- cache_slug_lookup!(slug, record) if record.present?
51
- end
52
- end
53
-
54
- # Returns a slug cache key for a given slug.
55
- def slug_cache_key(slug)
56
- [Pseudocephalopod.cache_key_prefix, slug_scope_key(Digest::SHA256.hexdigest(slug.to_s.strip))].compact.join("/")
57
- end
58
-
59
- def has_cache_for_slug?(slug)
60
- lookup_cached_id_from_slug(slug).present?
61
- end
62
-
63
- # Modify the cache for a given slug. If record is nil, it will
64
- # delete the item from the slug cache, otherwise it will store
65
- # the records id.
66
- def cache_slug_lookup!(slug, record)
67
- return if Pseudocephalopod.cache.blank?
68
- cache = Pseudocephalopod.cache
69
- key = slug_cache_key(slug)
70
- # Set an expires in option for caching.
71
- caching_options = Hash.new.tap do |hash|
72
- expiry = Pseudocephalopod::Caching.cache_expires_in
73
- hash[:expires_in] = expiry.to_i if expiry.present?
74
- end
75
- record.nil? ? cache.delete(key) : cache.write(key, record.id, caching_options)
76
- end
77
-
78
- protected
79
-
80
- def lookup_cached_id_from_slug(slug)
81
- Pseudocephalopod.cache && Pseudocephalopod.cache.read(slug_cache_key(slug))
82
- end
83
-
84
- end
85
-
86
- end
87
- end
@@ -1,19 +0,0 @@
1
- module Pseudocephalopod
2
- module Finders
3
-
4
- def find_using_slug(slug, options = {})
5
- slug = slug.to_s
6
- value = nil
7
- value ||= find_by_id(slug.to_i, options) if slug =~ /\A\d+\Z/
8
- value ||= with_cached_slug(slug).first(options)
9
- value ||= find_using_slug_history(slug, options) if use_slug_history
10
- value.found_via_slug = slug if value.present?
11
- value
12
- end
13
-
14
- def find_using_slug!(slug, options = {})
15
- find_using_slug(slug, options) or raise ActiveRecord::RecordNotFound
16
- end
17
-
18
- end
19
- end
@@ -1,29 +0,0 @@
1
- module Pseudocephalopod
2
- # Implements a simple cache store that uses the
3
- # current processes memory. This makes is primarily
4
- # used for testing purposes in the situations where
5
- # caching is used.
6
- class MemoryCache
7
-
8
- def self.write(key, value, options = {})
9
- cache[key.to_s] = value
10
- end
11
-
12
- def self.read(key)
13
- cache[key.to_s]
14
- end
15
-
16
- def self.delete(key)
17
- cache.delete key.to_s
18
- end
19
-
20
- def self.reset!
21
- @cache = nil
22
- end
23
-
24
- def self.cache
25
- @cache ||= {}
26
- end
27
-
28
- end
29
- end
@@ -1,9 +0,0 @@
1
- module Pseudocephalopod
2
- class Railtie < Rails::Railtie
3
-
4
- initializer "pseudocephalopod.initialize_cache" do
5
- Pseudocephalopod.cache = Rails.cache if Rails.cache.present?
6
- end
7
-
8
- end
9
- end