Skip to content

Commit

Permalink
Began refactoring into adapters. Removed more code smells detected by…
Browse files Browse the repository at this point in the history
… reek.
  • Loading branch information
norman committed Jan 8, 2010
1 parent 8bf9a0a commit ce05963
Show file tree
Hide file tree
Showing 21 changed files with 720 additions and 445 deletions.
7 changes: 7 additions & 0 deletions History.txt
@@ -1,3 +1,10 @@
== 2.3.0 NOT RELEASED

* 1 major enhancement
* Major refactorings, cleanups and deprecations en route to the 3.0 release.
* 1 minor enhancement
* New option to pass arguments to approximate_ascii, allowing custom approximations specific to German or Spanish.

== 2.2.7 2009-12-16

* 1 minor fix
Expand Down
23 changes: 15 additions & 8 deletions README.rdoc
Expand Up @@ -53,13 +53,13 @@ models by numeric id, you can detect whether they were found by the
friendly_id:

@post = Post.find(params[:id])
raise "some error" if !@post.found_using_friendly_id?
raise "some error" if @post.friendly_id_status.unfriendly?

or, you can 301 redirect if the model was found by the numeric id if you don't
care about numeric access, but want the SEO value of the friendly_id:

@post = Post.find(params[:id])
redirect_to @post, :status => 301 if @post.has_better_id?
redirect_to @post, :status => 301 unless @post.friendly_id_status.best?

The "has_better_id?" method returns true if the model was found with the
numeric id, or with an outdated slug.
Expand All @@ -79,7 +79,7 @@ to do a 301 redirect to your updated URL.
...

def ensure_current_post_url
redirect_to @post, :status => :moved_permanently if @post.has_better_id?
redirect_to @post, :status => :moved_permanently unless @post.friendly_id_status.best?
end

end
Expand Down Expand Up @@ -215,7 +215,7 @@ FriendlyId's slugging can strip diacritics from Western European characters,
so that you can have ASCII-only URL's; for example, conveting "ñøîéçü" to
"noiecu."

has_friendly_id :title, :use_slug => true, :strip_diacritics => true
has_friendly_id :title, :use_slug => true, :approximate_ascii => true

If you are not using slugs, you'll have to do this manually for whatever value
you're using as the friendly_id.
Expand Down Expand Up @@ -249,19 +249,26 @@ that uses a non-Roman writing system, your feedback would be most welcome.
=== Custom Slug Generation

While FriendlyId's slug generation options work for most people, you may need
something else. As of version 2.0.4 you can pass in your own custom slug
generation block:
something else. As of version 2.3.0 you can simply override the
+normalize_friendly_id+ method in your model class:

class Post < ActiveRecord::Base
has_friendly_id :title, :use_slug => true do |text|
has_friendly_id :title, :use_slug => true

def normalize_friendly_id(text)
MySlugGeneratorClass::my_slug_method(text)
end

end

FriendlyId will still respect your settings for max length and reserved words,
but will use your block rather than the baked-in methods to normalize the
but will use your method rather than the baked-in methods to normalize the
friendly_id text.

Note that previous versions of friendly_id allowed this same functionality by
passing a block to +has_friendly_id+, but this is deprecated as of version
2.3.0.

== Getting it

FriendlyId is best installed as a Ruby Gem:
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Expand Up @@ -19,7 +19,7 @@ end
begin
require "yard"
YARD::Rake::YardocTask.new do |t|
t.options = ["--output-dir=docs"]
t.options = ["--output-dir=docs", "--private"]
end
rescue LoadError
end
Expand Down
75 changes: 75 additions & 0 deletions config.reek
@@ -0,0 +1,75 @@
---
LargeClass:
max_methods: 25
exclude: []

enabled: true
max_instance_variables: 9
LongParameterList:
max_params: 3
exclude: []

enabled: true
overrides:
initialize:
max_params: 5
FeatureEnvy:
exclude: &id001 [!ruby/regexp /=$/]

enabled: true
ClassVariable:
exclude: *id001
enabled: true
UncommunicativeName:
accept:
- Inline::C
exclude: []

enabled: true
reject:
- !ruby/regexp /^.$/
- !ruby/regexp /[0-9]$/
NestedIterators:
exclude: *id001
enabled: true
LongMethod:
max_statements: 5
exclude:
- initialize
enabled: true
Duplication:
exclude: []

enabled: true
max_calls: 2
UtilityFunction:
max_helper_calls: 1
exclude: []

enabled: true
Attribute:
exclude: []

enabled: false
SimulatedPolymorphism:
exclude: []

enabled: true
max_ifs: 2
DataClump:
exclude: []

enabled: true
max_copies: 2
min_clump_size: 2
ControlCouple:
exclude: *id001
enabled: true
LongYieldList:
max_params: 3
exclude: []

enabled: true
overrides:
initialize:
max_params: 5
24 changes: 10 additions & 14 deletions lib/friendly_id.rb
@@ -1,13 +1,7 @@
require File.join(File.dirname(__FILE__), "friendly_id", "helpers")
require File.join(File.dirname(__FILE__), "friendly_id", "slug")
require File.join(File.dirname(__FILE__), "friendly_id", "slug_string")
require File.join(File.dirname(__FILE__), "friendly_id", "config")
require File.join(File.dirname(__FILE__), "friendly_id", "slugged", "finder")
require File.join(File.dirname(__FILE__), "friendly_id", "slugged", "class_methods")
require File.join(File.dirname(__FILE__), "friendly_id", "slugged", "instance_methods")
require File.join(File.dirname(__FILE__), "friendly_id", "simple", "class_methods")
require File.join(File.dirname(__FILE__), "friendly_id", "simple", "instance_methods")

require File.join(File.dirname(__FILE__), "friendly_id", "finder")
require File.join(File.dirname(__FILE__), "friendly_id", "status")
# FriendlyId is a comprehensive Ruby library for slugging and permalinks with
# ActiveRecord.
# @author Norman Clarke
Expand Down Expand Up @@ -57,16 +51,18 @@ def self.parse_friendly_id(string)
return name, sequence
end


private

# Load either the SluggedModel or SimpleModel modules.
# @TODO figure out best way to selectively load adapted modules
def load_adapters
require File.join(File.dirname(__FILE__), "friendly_id", "adapters", "active_record", "simple_model")
require File.join(File.dirname(__FILE__), "friendly_id", "adapters", "active_record", "slugged_model")
require File.join(File.dirname(__FILE__), "friendly_id", "adapters", "active_record", "slug")
if friendly_id_config.use_slug?
extend Slugged::ClassMethods
include Slugged::InstanceMethods
include Adapters::ActiveRecord::SluggedModel
else
extend Simple::ClassMethods
include Simple::InstanceMethods
include Adapters::ActiveRecord::SimpleModel
end
end

Expand All @@ -76,4 +72,4 @@ def load_adapters
# ActiveRecord::Base.
class ActiveRecord::Base
extend FriendlyId
end
end
133 changes: 133 additions & 0 deletions lib/friendly_id/adapters/active_record/simple_model.rb
@@ -0,0 +1,133 @@
module FriendlyId
module Adapters
module ActiveRecord

module SimpleModel

class Finder < FriendlyId::Finder

def column
"#{table_name}.#{friendly_id_config.method}"
end

def primary_key
"#{quoted_table_name}.#{model.send :primary_key}"
end

end

class MultipleFinder < Finder

attr_reader :friendly_ids, :results, :unfriendly_ids

def initialize(ids, model, options={})
@friendly_ids, @unfriendly_ids = ids.partition {|id| self.class.friendly?(id) && id.to_s }
super
end

def error_message
"Couldn't find all %s with IDs (%s) AND %s (found %d results, but was looking for %d)" % [
model.name.pluralize,
ids * ', ',
sanitize_sql(options[:conditions]),
results.size,
expected_size
]
end

def find
@results = with_scope(:find => options) { all(:conditions => conditions) }
raise(::ActiveRecord::RecordNotFound, error_message) if @results.size != expected_size
friendly_results.each { |result| result.friendly_id_status.name = result.friendly_id }
@results
end

def friendly_results
results.select { |result| friendly_ids.include? result.friendly_id.to_s }
end

def conditions
["#{primary_key} IN (?) OR #{column} IN (?)", unfriendly_ids, friendly_ids]
end

end

class SingleFinder < Finder

def find
result = with_scope(:find => find_options) { find_initial options }
raise ::ActiveRecord::RecordNotFound.new if !result
result.friendly_id_status.name = id
result
end

def find_options
{:conditions => {column => id}}
end

end

class Status < FriendlyId::Status
# Did the find operation use a friendly id?
def friendly?
!! name
end
alias :best? :friendly?
end

module Finders
def find_one(id, options)
finder = SingleFinder.new(id, self, options)
finder.unfriendly? ? super : finder.find
end

def find_some(ids_and_names, options)
MultipleFinder.new(ids_and_names, self, options).find
end
protected :find_one, :find_some
end

def self.included(base)
base.validate :validate_friendly_id
base.extend Finders
end

def friendly_id_status
@friendly_id_status ||= Status.new(:model => self)
end

# Was the record found using one of its friendly ids?
def found_using_friendly_id?
friendly_id_status.friendly?
end

# Was the record found using its numeric id?
def found_using_numeric_id?
friendly_id_status.numeric?
end
alias has_better_id? found_using_numeric_id?

# Returns the friendly_id.
def friendly_id
send friendly_id_config.method
end
alias best_id friendly_id

# Returns the friendly id, or if none is available, the numeric id.
def to_param
(friendly_id || id).to_s
end

private

def validate_friendly_id
if result = friendly_id_config.reserved_error_message(friendly_id)
self.errors.add(*result)
return false
end
end

end
end
end
end
File renamed without changes.

0 comments on commit ce05963

Please sign in to comment.