seo_friendly 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +70 -0
- data/Rakefile +2 -0
- data/lib/generators/seo_friendly/install/USAGE +2 -0
- data/lib/generators/seo_friendly/install/install_generator.rb +23 -0
- data/lib/generators/seo_friendly/install/templates/default_seo_source.rb +31 -0
- data/lib/generators/seo_friendly/install/templates/migrations/create_seo_params.rb +18 -0
- data/lib/models/seo_param.rb +6 -0
- data/lib/railtie.rb +10 -0
- data/lib/seo_friendly.rb +19 -0
- data/lib/seo_friendly/constructors/meta_constructors.rb +41 -0
- data/lib/seo_friendly/data_extractor.rb +33 -0
- data/lib/seo_friendly/exceptions.rb +51 -0
- data/lib/seo_friendly/model_helper.rb +12 -0
- data/lib/seo_friendly/renderer/meta_render.rb +15 -0
- data/lib/seo_friendly/seo_creator.rb +13 -0
- data/lib/seo_friendly/seo_params_processor.rb +28 -0
- data/lib/seo_friendly/seo_searcher.rb +19 -0
- data/lib/seo_friendly/seo_updater.rb +14 -0
- data/lib/seo_friendly/source_searcher.rb +39 -0
- data/lib/seo_friendly/version.rb +3 -0
- data/lib/seo_friendly/view_helper.rb +19 -0
- data/lib/seo_friendly/words_splitter.rb +26 -0
- data/lib/tasks/rebuild_seo_params.rake +20 -0
- data/seo_friendly.gemspec +24 -0
- metadata +113 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: e8ead4473d9c8e7226c5d09105070a7d2da6e00f
|
|
4
|
+
data.tar.gz: ce7b8a84efba8f92fbc403a1dc0fe2ff8321eca6
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 034b279d5ac1cc1f79110c1b07f0b0b60826262bcb8c2567cb8ae2f1cf81d6d95f014a5446e122d52716f45951a61b74dcb1b7f1d5e6093d0abed54abc17dd0d
|
|
7
|
+
data.tar.gz: f83ec0f07cc899190f081f06073a9b0c8a8ee4bce713f784bec9bb2fd7a95e3e0e212b483445f80031e3af77e137078a60f60fb66fa3c2cb31bf4ab31e506dd5
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2015 buzhenko
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# SeoFriendly
|
|
2
|
+
|
|
3
|
+
SeoFriendly gem provides easy way to insert meta information (title, description, keywords) on almost all pages of your application.
|
|
4
|
+
Gem extract meta information for model from it's fields or from any source you specify.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
gem 'seo_friendly'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
For fast gem integration run generator that copy migration files and default source config into your application.
|
|
13
|
+
Gem use monkey patching to add new methods to ActiveRecord and new view helpers.
|
|
14
|
+
|
|
15
|
+
$ rails generate seo_friendly:install
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
Create your own seo source class for any model and specify information which will be used to create meta tags.
|
|
20
|
+
Example:
|
|
21
|
+
```ruby
|
|
22
|
+
# seo source class for Page model
|
|
23
|
+
class PageSeoSource < DefaultSeoSource
|
|
24
|
+
|
|
25
|
+
# title information will be extracted from title field of Page instance
|
|
26
|
+
def title
|
|
27
|
+
instance.title
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# description will be always constant for Page
|
|
31
|
+
def description
|
|
32
|
+
'Awesome pages of my beautiful application'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Page model can have for example tags reference that you can use to generate keywords.
|
|
36
|
+
def keywords
|
|
37
|
+
instance.tags.join(' ,')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Views
|
|
44
|
+
On views you can insert meta tags using helper
|
|
45
|
+
|
|
46
|
+
```haml
|
|
47
|
+
= meta_tags(@page) %>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Model
|
|
51
|
+
To update meta information every time when you update records add to model callback:
|
|
52
|
+
```ruby
|
|
53
|
+
after_save :update_seo_attributes
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Rake
|
|
57
|
+
If you change model source and want to update seo information for all instances of this model you can use rake task
|
|
58
|
+
|
|
59
|
+
$ rake seo_friendly:regenerate[ModelName]
|
|
60
|
+
|
|
61
|
+
## TODO
|
|
62
|
+
2) Add tests
|
|
63
|
+
6) WordsSplitter is too slow, replace it with regular expression (change)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
1. Fork it ( https://github.com/rossmari/seo_friendly/fork )
|
|
67
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
68
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
69
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
70
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module SeoFriendly
|
|
2
|
+
module Generators
|
|
3
|
+
class InstallGenerator < ::Rails::Generators::Base
|
|
4
|
+
include Rails::Generators::Migration
|
|
5
|
+
|
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
7
|
+
|
|
8
|
+
# TODO : rename method
|
|
9
|
+
def copy_default_seo_source
|
|
10
|
+
template 'default_seo_source.rb', 'app/seo_sources/default_seo_source.rb'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def copy_migrations
|
|
14
|
+
migration_template 'migrations/create_seo_params.rb', 'db/migrate/create_seo_params.rb'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.next_migration_number(dir)
|
|
18
|
+
Time.now.utc.strftime('%Y%m%d%H%M%S')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class DefaultSeoSource
|
|
2
|
+
attr_reader :instance
|
|
3
|
+
|
|
4
|
+
def initialize(instance)
|
|
5
|
+
@instance = instance
|
|
6
|
+
|
|
7
|
+
@title = title
|
|
8
|
+
@description = description
|
|
9
|
+
@keywords = keywords
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def title
|
|
13
|
+
instance.title
|
|
14
|
+
rescue
|
|
15
|
+
'Default SeoFriendly title'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def description
|
|
19
|
+
instance.description
|
|
20
|
+
rescue
|
|
21
|
+
'Default SeoFriendly description'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def keywords
|
|
25
|
+
instance.keywords
|
|
26
|
+
rescue
|
|
27
|
+
'Default SeoFriendly keywords'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class SeoFriendly < ActiveRecord::Migration
|
|
2
|
+
|
|
3
|
+
def change
|
|
4
|
+
create_table :seo_params do |t|
|
|
5
|
+
t.string :description
|
|
6
|
+
t.string :title
|
|
7
|
+
t.string :keywords
|
|
8
|
+
|
|
9
|
+
t.integer :searchable_id
|
|
10
|
+
t.string :searchable_type
|
|
11
|
+
|
|
12
|
+
t.timestamps null: false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
add_index :seo_params, [ :searchable_id, :searchable_type ]
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/railtie.rb
ADDED
data/lib/seo_friendly.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'action_view'
|
|
2
|
+
require 'seo_friendly/version'
|
|
3
|
+
require 'seo_friendly/seo_searcher'
|
|
4
|
+
require 'seo_friendly/exceptions'
|
|
5
|
+
require 'seo_friendly/renderer/meta_render'
|
|
6
|
+
require 'seo_friendly/view_helper'
|
|
7
|
+
require 'seo_friendly/model_helper'
|
|
8
|
+
require 'active_record'
|
|
9
|
+
require 'models/seo_param'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
module SeoFriendly
|
|
13
|
+
|
|
14
|
+
ActionView::Base.send :include, SeoFriendly::ViewHelper
|
|
15
|
+
ActiveRecord::Base.send :include, SeoFriendly::ModelHelper
|
|
16
|
+
|
|
17
|
+
require 'railtie' if defined?(Rails)
|
|
18
|
+
|
|
19
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#TODO RENAME TO META CONSTRUCTORS or META parsers
|
|
2
|
+
#TODO: add html escaping for data
|
|
3
|
+
require 'seo_friendly/words_splitter'
|
|
4
|
+
|
|
5
|
+
module SeoFriendly
|
|
6
|
+
|
|
7
|
+
# Recommended title tag length: up to 70 characters, 10 words.
|
|
8
|
+
class TitleConstructor
|
|
9
|
+
|
|
10
|
+
def self.extract(object)
|
|
11
|
+
WordsSplitter.split(object, 70, 10)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class DescriptionConstructor
|
|
17
|
+
|
|
18
|
+
OMISSION = '...'
|
|
19
|
+
|
|
20
|
+
# Recommended description tag length: up to 160 characters.
|
|
21
|
+
# In my document maximal words count is 200
|
|
22
|
+
def self.extract(object)
|
|
23
|
+
# TODO : remove maximal words count some how
|
|
24
|
+
description = WordsSplitter.split(object, 200, 100)
|
|
25
|
+
unless description.end_with?('.')
|
|
26
|
+
description << OMISSION
|
|
27
|
+
end
|
|
28
|
+
return description
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class KeyWordsConstructor
|
|
34
|
+
|
|
35
|
+
def self.extract(object)
|
|
36
|
+
WordsSplitter.split(object, 255, 20)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'seo_friendly/constructors/meta_constructors'
|
|
2
|
+
module SeoFriendly
|
|
3
|
+
|
|
4
|
+
class DataExtractor
|
|
5
|
+
|
|
6
|
+
attr_reader :source, :title, :description, :keywords
|
|
7
|
+
|
|
8
|
+
# a little bit of metaprogramming
|
|
9
|
+
EXTRACTORS = { title: TitleConstructor, description: DescriptionConstructor, keywords: KeyWordsConstructor }
|
|
10
|
+
|
|
11
|
+
def initialize(source)
|
|
12
|
+
@source = source
|
|
13
|
+
extract_information
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def seo_attributes
|
|
17
|
+
{ title: title, description: description, keywords: keywords }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def extract_information
|
|
23
|
+
EXTRACTORS.each do |attribute_name, extractor_class|
|
|
24
|
+
instance_variable_set("@#{attribute_name}", extractor_class.send(:extract, source.send(attribute_name)))
|
|
25
|
+
end
|
|
26
|
+
rescue => exception
|
|
27
|
+
raise ExtractDataFromSourceError.new(source.class.name, exception.message)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module SeoFriendly
|
|
2
|
+
|
|
3
|
+
class SourceNotDefinedError < StandardError
|
|
4
|
+
|
|
5
|
+
MESSAGE = 'Unable to find seo rule %{policy_name} for %{object} class'
|
|
6
|
+
|
|
7
|
+
attr_reader :object
|
|
8
|
+
|
|
9
|
+
def initialize(policy, object)
|
|
10
|
+
super( MESSAGE % { policy_name: policy, object: object} )
|
|
11
|
+
@object = object
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class UnknownSeoAttributeError < StandardError
|
|
17
|
+
|
|
18
|
+
MESSAGE = 'Unknown seo attribute method \'%{seo_method}\' for field \'%{seo_field}\'.'
|
|
19
|
+
|
|
20
|
+
attr_reader :object
|
|
21
|
+
|
|
22
|
+
def initialize(seo_field, seo_method)
|
|
23
|
+
super( MESSAGE % { seo_field: seo_field, seo_method: seo_method } )
|
|
24
|
+
@object = object
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class UnknownSeoModeError < StandardError
|
|
30
|
+
|
|
31
|
+
MESSAGE = 'Unknown seo mode value %{seo_mode}'
|
|
32
|
+
|
|
33
|
+
attr_reader :object
|
|
34
|
+
|
|
35
|
+
def initialize(mode)
|
|
36
|
+
super( MESSAGE % { seo_mode: mode} )
|
|
37
|
+
@object = object
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class ExtractDataFromSourceError < StandardError
|
|
43
|
+
MESSAGE = 'Failed to extract data from source %{source_name}. '
|
|
44
|
+
attr_reader :object
|
|
45
|
+
def initialize(source_name, stack_message)
|
|
46
|
+
super( MESSAGE % { source_name: source_name} << stack_message )
|
|
47
|
+
@object = object
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module SeoFriendly
|
|
2
|
+
|
|
3
|
+
class MetaRenderer
|
|
4
|
+
|
|
5
|
+
def self.render(container, context)
|
|
6
|
+
tags = ''
|
|
7
|
+
tags << context.content_tag(:meta, nil, content: container.title, name: 'title')
|
|
8
|
+
tags << context.content_tag(:meta, nil, content: container.description, name: 'description')
|
|
9
|
+
tags << context.content_tag(:meta, nil, content: container.keywords, name: 'keywords')
|
|
10
|
+
context.raw(tags)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'seo_friendly/source_searcher'
|
|
2
|
+
require 'seo_friendly/data_extractor'
|
|
3
|
+
require 'seo_friendly/seo_params_processor'
|
|
4
|
+
|
|
5
|
+
module SeoFriendly
|
|
6
|
+
class SeoCreator < SeoParamsProcessor
|
|
7
|
+
|
|
8
|
+
def create
|
|
9
|
+
SeoParam.create(extracted_seo_attributes.merge(searchable: instance))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'seo_friendly/source_searcher'
|
|
2
|
+
require 'seo_friendly/data_extractor'
|
|
3
|
+
|
|
4
|
+
module SeoFriendly
|
|
5
|
+
class SeoParamsProcessor
|
|
6
|
+
|
|
7
|
+
attr_reader :instance, :raw_data_source, :extracted_seo_attributes
|
|
8
|
+
|
|
9
|
+
def initialize(instance)
|
|
10
|
+
@instance = instance
|
|
11
|
+
@raw_data_source = create_data_source
|
|
12
|
+
@extracted_seo_attributes = extract_seo_attributes
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def create_data_source
|
|
18
|
+
source_class = SourceSearcher.new(instance).find_source
|
|
19
|
+
source_class.new(instance)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def extract_seo_attributes
|
|
23
|
+
extractor = DataExtractor.new(raw_data_source)
|
|
24
|
+
extractor.seo_attributes
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'seo_friendly/seo_creator'
|
|
2
|
+
module SeoFriendly
|
|
3
|
+
|
|
4
|
+
class SeoSearcher
|
|
5
|
+
|
|
6
|
+
attr_reader :id, :type
|
|
7
|
+
|
|
8
|
+
def initialize(searchable_id, searchable_type)
|
|
9
|
+
@id = searchable_id
|
|
10
|
+
@type = searchable_type
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def search
|
|
14
|
+
SeoParam.where(searchable_type: type, searchable_id: id).first
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'seo_friendly/source_searcher'
|
|
2
|
+
require 'seo_friendly/data_extractor'
|
|
3
|
+
require 'seo_friendly/seo_params_processor'
|
|
4
|
+
|
|
5
|
+
module SeoFriendly
|
|
6
|
+
class SeoUpdater < SeoParamsProcessor
|
|
7
|
+
|
|
8
|
+
def update
|
|
9
|
+
seo_record = SeoSearcher.new(instance.id, instance.class.name).search
|
|
10
|
+
seo_record.update_attributes(extracted_seo_attributes)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module SeoFriendly
|
|
2
|
+
class SourceSearcher
|
|
3
|
+
|
|
4
|
+
attr_reader :object
|
|
5
|
+
|
|
6
|
+
def initialize(model)
|
|
7
|
+
@object = model
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def find_source
|
|
11
|
+
source or raise SourceNotDefinedError.new(find, object)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def source
|
|
17
|
+
klass = find
|
|
18
|
+
klass = klass.constantize if klass.is_a?(String)
|
|
19
|
+
klass
|
|
20
|
+
rescue NameError
|
|
21
|
+
nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def find
|
|
25
|
+
klass = if object.respond_to?(:model_name)
|
|
26
|
+
object.model_name
|
|
27
|
+
elsif object.class.respond_to?(:model_name)
|
|
28
|
+
object.class.model_name
|
|
29
|
+
elsif object.is_a?(Class)
|
|
30
|
+
object
|
|
31
|
+
elsif object.is_a?(Symbol)
|
|
32
|
+
object.to_s.classify
|
|
33
|
+
else
|
|
34
|
+
object.class
|
|
35
|
+
end
|
|
36
|
+
"#{klass}SeoSource"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'seo_friendly/seo_searcher'
|
|
2
|
+
require 'seo_friendly/seo_creator'
|
|
3
|
+
|
|
4
|
+
module SeoFriendly
|
|
5
|
+
|
|
6
|
+
module ViewHelper
|
|
7
|
+
|
|
8
|
+
def meta_tags(instance)
|
|
9
|
+
container = SeoSearcher.new(instance.id, instance.class.name).search || SeoCreator.new(instance).create
|
|
10
|
+
MetaRenderer.render(container, self)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def meta_container(instance)
|
|
14
|
+
SeoSearcher.new(instance.id, instance.class.name).search || SeoCreator.new(instance).create
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module SeoFriendly
|
|
2
|
+
class WordsSplitter
|
|
3
|
+
|
|
4
|
+
def self.split(object, maximal_length, maximal_words_count)
|
|
5
|
+
if object.length <= maximal_length && words_count(object) <= maximal_words_count
|
|
6
|
+
return object
|
|
7
|
+
else
|
|
8
|
+
object = reduce_string(object)
|
|
9
|
+
split(object, maximal_length, maximal_words_count)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def self.words_count(object)
|
|
16
|
+
object.split.count
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.reduce_string(object)
|
|
20
|
+
array = object.split
|
|
21
|
+
array.delete(array.last)
|
|
22
|
+
array.join(' ')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
namespace :seo_friendly do
|
|
2
|
+
|
|
3
|
+
desc 'Regenerate seo params for chosen model'
|
|
4
|
+
task :regenerate, [:model_name] => :environment do |t, args|
|
|
5
|
+
|
|
6
|
+
unless args[:model_name]
|
|
7
|
+
abort('WARNING! Set model name parametr to execute this rake task')
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
model = args[:model_name].capitalize.constantize
|
|
11
|
+
|
|
12
|
+
model.find_each do |instance|
|
|
13
|
+
|
|
14
|
+
instance.update_seo_attributes
|
|
15
|
+
puts "Update seo attributes for #{instance.class.name} with ID #{instance.id}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'seo_friendly/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "seo_friendly"
|
|
8
|
+
spec.version = SeoFriendly::VERSION
|
|
9
|
+
spec.authors = ["buzhenko"]
|
|
10
|
+
spec.email = ["roman-bujenko@yandex.ru"]
|
|
11
|
+
spec.summary = %q{Seo }
|
|
12
|
+
spec.description = %q{Seo}
|
|
13
|
+
spec.homepage = ""
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
23
|
+
spec.add_development_dependency "activerecord", "~> 4.2.0"
|
|
24
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: seo_friendly
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- buzhenko
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-04-16 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.7'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.7'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: activerecord
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 4.2.0
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 4.2.0
|
|
55
|
+
description: Seo
|
|
56
|
+
email:
|
|
57
|
+
- roman-bujenko@yandex.ru
|
|
58
|
+
executables: []
|
|
59
|
+
extensions: []
|
|
60
|
+
extra_rdoc_files: []
|
|
61
|
+
files:
|
|
62
|
+
- ".gitignore"
|
|
63
|
+
- Gemfile
|
|
64
|
+
- LICENSE.txt
|
|
65
|
+
- README.md
|
|
66
|
+
- Rakefile
|
|
67
|
+
- lib/generators/seo_friendly/install/USAGE
|
|
68
|
+
- lib/generators/seo_friendly/install/install_generator.rb
|
|
69
|
+
- lib/generators/seo_friendly/install/templates/default_seo_source.rb
|
|
70
|
+
- lib/generators/seo_friendly/install/templates/migrations/create_seo_params.rb
|
|
71
|
+
- lib/models/seo_param.rb
|
|
72
|
+
- lib/railtie.rb
|
|
73
|
+
- lib/seo_friendly.rb
|
|
74
|
+
- lib/seo_friendly/constructors/meta_constructors.rb
|
|
75
|
+
- lib/seo_friendly/data_extractor.rb
|
|
76
|
+
- lib/seo_friendly/exceptions.rb
|
|
77
|
+
- lib/seo_friendly/model_helper.rb
|
|
78
|
+
- lib/seo_friendly/renderer/meta_render.rb
|
|
79
|
+
- lib/seo_friendly/seo_creator.rb
|
|
80
|
+
- lib/seo_friendly/seo_params_processor.rb
|
|
81
|
+
- lib/seo_friendly/seo_searcher.rb
|
|
82
|
+
- lib/seo_friendly/seo_updater.rb
|
|
83
|
+
- lib/seo_friendly/source_searcher.rb
|
|
84
|
+
- lib/seo_friendly/version.rb
|
|
85
|
+
- lib/seo_friendly/view_helper.rb
|
|
86
|
+
- lib/seo_friendly/words_splitter.rb
|
|
87
|
+
- lib/tasks/rebuild_seo_params.rake
|
|
88
|
+
- seo_friendly.gemspec
|
|
89
|
+
homepage: ''
|
|
90
|
+
licenses:
|
|
91
|
+
- MIT
|
|
92
|
+
metadata: {}
|
|
93
|
+
post_install_message:
|
|
94
|
+
rdoc_options: []
|
|
95
|
+
require_paths:
|
|
96
|
+
- lib
|
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
|
+
requirements:
|
|
99
|
+
- - ">="
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '0'
|
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
|
+
requirements:
|
|
104
|
+
- - ">="
|
|
105
|
+
- !ruby/object:Gem::Version
|
|
106
|
+
version: '0'
|
|
107
|
+
requirements: []
|
|
108
|
+
rubyforge_project:
|
|
109
|
+
rubygems_version: 2.4.5
|
|
110
|
+
signing_key:
|
|
111
|
+
specification_version: 4
|
|
112
|
+
summary: Seo
|
|
113
|
+
test_files: []
|