metaslug 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +6 -0
- data/MIT-LICENSE +20 -0
- data/README.md +112 -0
- data/Rakefile +19 -0
- data/lib/metaslug/controllers/action_controller_extension.rb +165 -0
- data/lib/metaslug/helpers/action_view_extension.rb +49 -0
- data/lib/metaslug/hooks.rb +15 -0
- data/lib/metaslug/railtie.rb +7 -0
- data/lib/metaslug/version.rb +3 -0
- data/lib/metaslug.rb +7 -0
- data/lib/rails/generators/metaslug/install/install_generator.rb +21 -0
- data/lib/rails/generators/metaslug/locale/locale_generator.rb +69 -0
- data/lib/tasks/metaslug_tasks.rake +4 -0
- data/metaslug.gemspec +24 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/assets/stylesheets/scaffold.css +56 -0
- data/test/dummy/app/controllers/application_controller.rb +13 -0
- data/test/dummy/app/controllers/categories_controller.rb +58 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/controllers/pages_controller.rb +12 -0
- data/test/dummy/app/controllers/posts_controller.rb +60 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/helpers/categories_helper.rb +2 -0
- data/test/dummy/app/helpers/metaslug_helper.rb +2 -0
- data/test/dummy/app/helpers/pages_helper.rb +2 -0
- data/test/dummy/app/helpers/posts_helper.rb +2 -0
- data/test/dummy/app/mailers/.keep +0 -0
- data/test/dummy/app/models/.keep +0 -0
- data/test/dummy/app/models/category.rb +3 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/models/page.rb +3 -0
- data/test/dummy/app/models/post.rb +5 -0
- data/test/dummy/app/views/categories/_form.html.erb +21 -0
- data/test/dummy/app/views/categories/edit.html.erb +6 -0
- data/test/dummy/app/views/categories/index.html.erb +25 -0
- data/test/dummy/app/views/categories/new.html.erb +5 -0
- data/test/dummy/app/views/categories/show.html.erb +9 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/pages/show.html.erb +1 -0
- data/test/dummy/app/views/posts/_form.html.erb +33 -0
- data/test/dummy/app/views/posts/edit.html.erb +6 -0
- data/test/dummy/app/views/posts/index.html.erb +31 -0
- data/test/dummy/app/views/posts/new.html.erb +5 -0
- data/test/dummy/app/views/posts/show.html.erb +24 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config/application.rb +23 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.example.yml +22 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +82 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/assets.rb +8 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/initializer.rb +1 -0
- data/test/dummy/config/initializers/metaslug.rb +1 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/de.yml +2 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/locales/fr.yml +23 -0
- data/test/dummy/config/metaslug/de.yml +4 -0
- data/test/dummy/config/metaslug/en.yml +61 -0
- data/test/dummy/config/metaslug/fr.yml +41 -0
- data/test/dummy/config/routes.rb +12 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/migrate/20140924091048_create_posts.rb +12 -0
- data/test/dummy/db/migrate/20140924091105_create_categories.rb +9 -0
- data/test/dummy/db/migrate/20140925101545_create_pages.rb +11 -0
- data/test/dummy/db/migrate/20140929145421_add_title_and_description_to_page.rb +6 -0
- data/test/dummy/db/schema.rb +43 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/test/fixtures/categories.yml +7 -0
- data/test/dummy/test/fixtures/pages.yml +23 -0
- data/test/dummy/test/fixtures/posts.yml +13 -0
- data/test/dummy/test/helpers/metaslug_helper_test.rb +25 -0
- data/test/dummy/test/integration/metas_test.rb +91 -0
- data/test/metaslug_test.rb +5 -0
- data/test/test_helper.rb +30 -0
- metadata +274 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5b1af058704bc625b6355a1c6ecf062f4d66e5bc
|
4
|
+
data.tar.gz: ce0ee9bb641e9f0a229bd9a417ab82768092d22c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7d67b7081bade2b06be9c5dd3c30bdd2d55ec258b583a3b423fb83a4ac5fb3c293733f6d2ed6f530944598344b580fd3594500598ace30cda95ed751eadc5133
|
7
|
+
data.tar.gz: dd0dbfd64162c81889557a93c9365d4a4fe280f60589b19a66981567409960d8f0c18b6cf5a4384ed0d72cf74f9345becd9a49b0aff516615da49d44783246bc
|
data/.gitignore
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
.bundle/
|
2
|
+
.config
|
3
|
+
.yardoc
|
4
|
+
log/*.log
|
5
|
+
pkg/
|
6
|
+
test/dummy/db/*.sqlite3
|
7
|
+
test/dummy/db/*.sqlite3-journal
|
8
|
+
test/dummy/log/*.log
|
9
|
+
test/dummy/tmp/
|
10
|
+
test/dummy/.sass-cache
|
11
|
+
test/dummy/config/database.yml
|
12
|
+
test/dummy/config/secrets.yml
|
13
|
+
vendor/bundle
|
14
|
+
Gemfile.lock
|
15
|
+
*.gem
|
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2014 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
# Metaslug
|
2
|
+
|
3
|
+
Metaslug allows you to map url to metas by locale.
|
4
|
+
You can define slug '/awesome-page' will have title 'Awesome' with other custom metas.
|
5
|
+
|
6
|
+
Metaslug uses liquid to be able to add dynamic content in the metas.
|
7
|
+
|
8
|
+
## Starting
|
9
|
+
|
10
|
+
First add the `metaslug` helper in your layout then use the install generator:
|
11
|
+
|
12
|
+
~~~
|
13
|
+
doctype html
|
14
|
+
html lang="fr"
|
15
|
+
head
|
16
|
+
meta charset="utf-8"
|
17
|
+
= metaslug
|
18
|
+
~~~
|
19
|
+
|
20
|
+
~~~
|
21
|
+
bundle exec rails generate metaslug:install
|
22
|
+
~~~
|
23
|
+
|
24
|
+
It will create the `config/metaslug` folder and add an initializer.
|
25
|
+
Locale files should be presents in this directory, but there is a task to help you generating them using your defined routes.
|
26
|
+
|
27
|
+
~~~
|
28
|
+
bundle exec rails generate metaslug:locale
|
29
|
+
~~~
|
30
|
+
|
31
|
+
It will generate files like:
|
32
|
+
|
33
|
+
~~~
|
34
|
+
en:
|
35
|
+
default:
|
36
|
+
description: "Default description"
|
37
|
+
title: "Default title"
|
38
|
+
"/posts":
|
39
|
+
description: ""
|
40
|
+
title: ""
|
41
|
+
"/posts/:id/edit":
|
42
|
+
description: ""
|
43
|
+
title: ""
|
44
|
+
~~~
|
45
|
+
|
46
|
+
This generator takes options. For example:
|
47
|
+
|
48
|
+
~~~
|
49
|
+
bundle exec rails g metaslug:locale -l eueui -o -m description,keywords,title
|
50
|
+
~~~
|
51
|
+
|
52
|
+
will take generate a file for de locale. `-o` specifies to only print content on the console while `-m` takes your metas (defaults are title and description).
|
53
|
+
|
54
|
+
On development mode, translations are reloaded for each request, not in the other environments.
|
55
|
+
|
56
|
+
You can edit your locale file to add static or dynamic content.
|
57
|
+
|
58
|
+
~~~
|
59
|
+
en:
|
60
|
+
default:
|
61
|
+
description: "Default description"
|
62
|
+
title: "Default title"
|
63
|
+
"/my-page":
|
64
|
+
description: ""
|
65
|
+
title: "Title"
|
66
|
+
"/posts/:id/edit":
|
67
|
+
description: "Edit a post"
|
68
|
+
title: "Edit post with title {{post.title}}"
|
69
|
+
~~~
|
70
|
+
|
71
|
+
We use liquid templates to be able to add dynamic content, based on your vars.
|
72
|
+
All you have to do is to allow methods in your model, and add allow variable in your controllers (they must be instance variable).
|
73
|
+
`metaslug_vars` is just a before_filter and can take the exact same options, like only, except…
|
74
|
+
|
75
|
+
~~~
|
76
|
+
class Post < ActiveRecord::Base
|
77
|
+
liquid_methods :title
|
78
|
+
end
|
79
|
+
~~~
|
80
|
+
|
81
|
+
~~~
|
82
|
+
class PostsController < ApplicationController
|
83
|
+
before_action :set_post, only: [:show, :edit, :update, :destroy]
|
84
|
+
metaslug_vars :post, only: :edit
|
85
|
+
|
86
|
+
private
|
87
|
+
def set_post
|
88
|
+
@post = Post.find(params[:id])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
~~~
|
92
|
+
|
93
|
+
## Tests
|
94
|
+
|
95
|
+
You can run the integration tests using:
|
96
|
+
|
97
|
+
~~~
|
98
|
+
bundle exec rake test
|
99
|
+
~~~
|
100
|
+
|
101
|
+
## Warning
|
102
|
+
|
103
|
+
Metaslug overrides the default render method, to be able to use dynamic metas.
|
104
|
+
We need to access the vars setted after action and interpolate them before rendering.
|
105
|
+
|
106
|
+
## Roadmap
|
107
|
+
|
108
|
+
This is what we planned to add next:
|
109
|
+
|
110
|
+
- Different storage (database, cache…)
|
111
|
+
- Web interface to edit metas from the app
|
112
|
+
- Remove rails dependency
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
Bundler::GemHelper.install_tasks
|
8
|
+
|
9
|
+
require 'rake/testtask'
|
10
|
+
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.libs << 'lib'
|
13
|
+
t.libs << 'test'
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
15
|
+
t.verbose = false
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
task default: :test
|
@@ -0,0 +1,165 @@
|
|
1
|
+
module Metaslug
|
2
|
+
module ActionControllerExtension
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
included do
|
5
|
+
|
6
|
+
#
|
7
|
+
# Initialise the traduction hash, load every metas into it.
|
8
|
+
# We only do this once, unless it is the development environment.
|
9
|
+
#
|
10
|
+
# @return [void] [Load metas of the current page]
|
11
|
+
def load_metas_for_current_slug
|
12
|
+
# initialize storage to an empty Hash, unless already exists
|
13
|
+
initialize_metas_storage
|
14
|
+
load_all_metas if Rails.env.development? or metas_storage.empty?
|
15
|
+
set_metas_for_current_path
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# A locale corresponds to a YAML file. We load each YAML file individually
|
20
|
+
# then merge then into a global hash.
|
21
|
+
#
|
22
|
+
# @return [Hash] [Global hash with all metas]
|
23
|
+
def load_all_metas
|
24
|
+
Thread.current[:metas] = I18n.available_locales.inject({}) do |acc, locale|
|
25
|
+
acc.merge!(load_metas_for_locale(locale))
|
26
|
+
acc
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Load a YAML file corresponding to a locale after ensuring it exists.
|
32
|
+
# @param locale [Symbol] [Locale]
|
33
|
+
#
|
34
|
+
# @return [Hash] [Metas]
|
35
|
+
def load_metas_for_locale(locale)
|
36
|
+
path = metas_path(locale)
|
37
|
+
if File.exists?(path)
|
38
|
+
YAML.load(File.open(path))
|
39
|
+
else
|
40
|
+
logger.error "[Metaslug] #{path} not found."
|
41
|
+
{}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Search and load metas of the current path.
|
47
|
+
#
|
48
|
+
# @return [void]
|
49
|
+
def set_metas_for_current_path
|
50
|
+
locale_metas_storage.keys.each do |k|
|
51
|
+
if request.path.match(translate_key_into_regexp(k))
|
52
|
+
set_metas_from_hash(locale_metas_storage[k])
|
53
|
+
return
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# if no key match the current path, load default metas if present.
|
58
|
+
if locale_metas_storage.has_key?('default')
|
59
|
+
set_metas_from_hash(locale_metas_storage['default'])
|
60
|
+
else
|
61
|
+
set_metas_from_hash({})
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Load metas into an instance variable to have access to them in the helper.
|
67
|
+
# Get the instance variables mark as accessible in the before_filter to interpolate
|
68
|
+
# values in the liquid template.
|
69
|
+
# @param values [Hash] [Metas]
|
70
|
+
#
|
71
|
+
# @return [Hash] [Metas]
|
72
|
+
def set_metas_from_hash(values)
|
73
|
+
@metaslug_vars ||= []
|
74
|
+
# For each meta we need to interpole the value if it use a dynamic content.
|
75
|
+
values.each do |k ,v|
|
76
|
+
if v.is_a?(Hash)
|
77
|
+
# recursive call for nested hash like { 'og' => { 'locale' => { 'alternate' => 'fr_FR' } } }
|
78
|
+
set_metas_from_hash(v)
|
79
|
+
else
|
80
|
+
# Looks like a liquid template
|
81
|
+
if v =~ /{{.*}}/
|
82
|
+
if @metaslug_vars.empty?
|
83
|
+
Rails.logger.debug "You provide a template but don't set access to your vars in the associated controller."
|
84
|
+
values[k] = v
|
85
|
+
else
|
86
|
+
template = Liquid::Template.parse(v)
|
87
|
+
h = @metaslug_vars.inject({}) do |acc, v|
|
88
|
+
acc[v.to_s] = instance_variable_get("@#{v}")
|
89
|
+
acc
|
90
|
+
end
|
91
|
+
values[k] = template.render(h)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
@metaslug = values
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# Return path of the YAML file of this locale.
|
101
|
+
# @param locale [Symbol] [Locale]
|
102
|
+
#
|
103
|
+
# @return [Pathname] [Path of the YAML file]
|
104
|
+
def metas_path(locale)
|
105
|
+
# TODO: Let user configure it.
|
106
|
+
Rails.root.join('config', 'metaslug', "#{locale}.yml")
|
107
|
+
end
|
108
|
+
|
109
|
+
#
|
110
|
+
# Metas of the given locale
|
111
|
+
# @param locale = I18n.locale [Symbol] [Locale]
|
112
|
+
#
|
113
|
+
# @return [Hash] [Metas]
|
114
|
+
def locale_metas_storage(locale = I18n.locale)
|
115
|
+
metas_storage[I18n.locale.to_s]
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# Backend storage of the metas. We store it in the current thread to avoid
|
120
|
+
# reloading it.
|
121
|
+
#
|
122
|
+
# @return [Hash] [Global metas]
|
123
|
+
def metas_storage
|
124
|
+
Thread.current[:metas]
|
125
|
+
end
|
126
|
+
|
127
|
+
#
|
128
|
+
# Initialize storage to an empty hash, unless already set.
|
129
|
+
#
|
130
|
+
# @return [Hash] [Global metas]
|
131
|
+
def initialize_metas_storage
|
132
|
+
Thread.current[:metas] ||= {}
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# YAML entries may looks like routes, like /categories/:id/edit. To be able
|
137
|
+
# to test these entries, we convert them to regexp, replacing :id (and others sym)
|
138
|
+
# @param k [String] [key]
|
139
|
+
#
|
140
|
+
# @return [Regexp] [Builded regexp]
|
141
|
+
def translate_key_into_regexp(k)
|
142
|
+
# replace :id with regular expression
|
143
|
+
%r{^#{k.gsub /\:\w+/, '[a-z0-9_.-]+'}$}i
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.metaslug_vars(*args)
|
147
|
+
before_filter args.extract_options! do
|
148
|
+
@metaslug_vars = args
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
# Overriding the default render method because we need to use the action
|
154
|
+
# variables to render the liquid template. This had to be done after the
|
155
|
+
# action and before the render.
|
156
|
+
# @param *args [Array] [Default arguments]
|
157
|
+
#
|
158
|
+
# @return [type] [description]
|
159
|
+
def render(*args)
|
160
|
+
load_metas_for_current_slug
|
161
|
+
super
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Metaslug
|
2
|
+
module ActionViewExtension
|
3
|
+
def metaslug
|
4
|
+
@metaslug.inject([]) do |acc, (k, v)|
|
5
|
+
if 'title' == k.to_s
|
6
|
+
acc << content_tag(:title, @metaslug['title'])
|
7
|
+
elsif v.is_a?(Hash)
|
8
|
+
# more complicated metas, like property
|
9
|
+
set_metas_from_hash(v, k, acc)
|
10
|
+
else
|
11
|
+
acc << content_tag(:meta, nil, { name: k.to_s, content: @metaslug[k.to_s] })
|
12
|
+
end
|
13
|
+
acc
|
14
|
+
end.join.html_safe
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
#
|
19
|
+
# Recursive function to build metas and add them to the accumulator.
|
20
|
+
# @param hash [Hash] [Hash of the metas]
|
21
|
+
# @param key [String] [Key of the parent hash]
|
22
|
+
# @param acc [Array] [Metas accumulator]
|
23
|
+
# @param separator = ':' [String] [Separator used when building key, ex: og:title]
|
24
|
+
#
|
25
|
+
# @return [type] [description]
|
26
|
+
def set_metas_from_hash(hash, key, acc, separator = ':')
|
27
|
+
hash.each do |k, v|
|
28
|
+
if v.is_a?(Hash)
|
29
|
+
_k = build_meta_name(key, k, separator)
|
30
|
+
set_metas_from_hash(v, _k, acc)
|
31
|
+
else
|
32
|
+
_k = build_meta_name(key, k, separator)
|
33
|
+
acc << content_tag(:meta, nil, { property: _k, content: v })
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Construct meta name based on the previous keys
|
40
|
+
# @param base_key [String] [Key of the parent hash, ex: og]
|
41
|
+
# @param key [String] [Key of the actual hash, ex: title]
|
42
|
+
# @param separator = ':' [String] [Separator used when building key, ex: og:title]
|
43
|
+
#
|
44
|
+
# @return [type] [description]
|
45
|
+
def build_meta_name(base_key, key, separator = ':')
|
46
|
+
base_key.present? ? "#{base_key}#{separator}#{key}" : key
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Metaslug
|
2
|
+
class Hooks
|
3
|
+
def self.init
|
4
|
+
ActiveSupport.on_load(:action_controller) do
|
5
|
+
require 'metaslug/controllers/action_controller_extension'
|
6
|
+
::ActionController::Base.send :include, Metaslug::ActionControllerExtension
|
7
|
+
end
|
8
|
+
|
9
|
+
ActiveSupport.on_load(:action_view) do
|
10
|
+
require 'metaslug/helpers/action_view_extension'
|
11
|
+
::ActionView::Base.send :include, Metaslug::ActionViewExtension
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/metaslug.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Metaslug
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
def self.banner
|
5
|
+
<<-BANNER.chomp
|
6
|
+
rails generate metaslug:install
|
7
|
+
|
8
|
+
Create locale's folder and initializer.
|
9
|
+
BANNER
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_locales_folder
|
13
|
+
empty_directory "config/metaslug"
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate_install_file
|
17
|
+
create_file "config/initializers/metaslug.rb", "require 'liquid'"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Metaslug
|
2
|
+
module Generators
|
3
|
+
class LocaleGenerator < Rails::Generators::Base
|
4
|
+
class_option :locale, type: :string, aliases: '-l', desc: "Generate a locale file base on the routes."
|
5
|
+
class_option :output, type: :string, aliases: '-o', desc: "Do not create file, just output buffer."
|
6
|
+
class_option :metas, type: :string, aliases: '-m', desc: "Define the metas you want to use."
|
7
|
+
|
8
|
+
def self.banner
|
9
|
+
<<-BANNER.chomp
|
10
|
+
rails generate metaslug:locale
|
11
|
+
|
12
|
+
Try to generate the metas file of the given locale, based on the current routes.
|
13
|
+
BANNER
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate_locale_file
|
17
|
+
routes = get_paths_from_routes
|
18
|
+
|
19
|
+
locales = options.locale? ?
|
20
|
+
[options.locale] :
|
21
|
+
I18n.available_locales
|
22
|
+
|
23
|
+
metas = options.metas? ?
|
24
|
+
options.metas.split(',') :
|
25
|
+
["description", "title"]
|
26
|
+
|
27
|
+
locales.each do |locale|
|
28
|
+
buffer = "#{locale}:\n"
|
29
|
+
add_metas_to_buffer(buffer, 'default', { quote_section: false }, *metas)
|
30
|
+
|
31
|
+
routes.each do |route|
|
32
|
+
add_metas_to_buffer(buffer, route, { quote_section: true }, *metas)
|
33
|
+
end
|
34
|
+
|
35
|
+
if options.output?
|
36
|
+
$stdout.puts buffer
|
37
|
+
else
|
38
|
+
create_file "config/metaslug/#{locale}.yml", buffer
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def add_metas_to_buffer(buffer, section, options = {}, *args)
|
45
|
+
spaces = ' ' * 2
|
46
|
+
if options[:quote_section]
|
47
|
+
buffer << "#{spaces}\"#{section}\":\n"
|
48
|
+
else
|
49
|
+
buffer << "#{spaces}#{section}:\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
args.each do |meta|
|
53
|
+
buffer << "#{spaces * 2}\"#{meta}\": \"\"\n"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_paths_from_routes
|
58
|
+
Rails.application.routes.routes.map do |route|
|
59
|
+
path = route.path.spec.to_s
|
60
|
+
# only keep GET url
|
61
|
+
next unless "GET".match route.verb.to_s
|
62
|
+
next if path.starts_with?('/assets') or path.starts_with?('/rails')
|
63
|
+
# remove (.:format), this is a bit dirty
|
64
|
+
$1 if path.match /(.*)\(.*/
|
65
|
+
end.compact.uniq
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/metaslug.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
require "metaslug/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "metaslug"
|
7
|
+
s.version = Metaslug::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Martin Catty"]
|
10
|
+
s.email = ["mcatty@synbioz.com"]
|
11
|
+
s.homepage = "https://github.com/synbioz/metaslug"
|
12
|
+
s.summary = "Set metas according to a path."
|
13
|
+
s.description = "Metaslug allows you to set your metas information in a localized YAML file."
|
14
|
+
s.license = "MIT"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
|
19
|
+
s.add_dependency "rails", "~> 4.0"
|
20
|
+
s.add_dependency "liquid"
|
21
|
+
|
22
|
+
s.add_development_dependency "capybara"
|
23
|
+
s.add_development_dependency "sqlite3"
|
24
|
+
end
|
data/test/dummy/Rakefile
ADDED
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any styles
|
10
|
+
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
|
11
|
+
* file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,56 @@
|
|
1
|
+
body { background-color: #fff; color: #333; }
|
2
|
+
|
3
|
+
body, p, ol, ul, td {
|
4
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
5
|
+
font-size: 13px;
|
6
|
+
line-height: 18px;
|
7
|
+
}
|
8
|
+
|
9
|
+
pre {
|
10
|
+
background-color: #eee;
|
11
|
+
padding: 10px;
|
12
|
+
font-size: 11px;
|
13
|
+
}
|
14
|
+
|
15
|
+
a { color: #000; }
|
16
|
+
a:visited { color: #666; }
|
17
|
+
a:hover { color: #fff; background-color:#000; }
|
18
|
+
|
19
|
+
div.field, div.actions {
|
20
|
+
margin-bottom: 10px;
|
21
|
+
}
|
22
|
+
|
23
|
+
#notice {
|
24
|
+
color: green;
|
25
|
+
}
|
26
|
+
|
27
|
+
.field_with_errors {
|
28
|
+
padding: 2px;
|
29
|
+
background-color: red;
|
30
|
+
display: table;
|
31
|
+
}
|
32
|
+
|
33
|
+
#error_explanation {
|
34
|
+
width: 450px;
|
35
|
+
border: 2px solid red;
|
36
|
+
padding: 7px;
|
37
|
+
padding-bottom: 0;
|
38
|
+
margin-bottom: 20px;
|
39
|
+
background-color: #f0f0f0;
|
40
|
+
}
|
41
|
+
|
42
|
+
#error_explanation h2 {
|
43
|
+
text-align: left;
|
44
|
+
font-weight: bold;
|
45
|
+
padding: 5px 5px 5px 15px;
|
46
|
+
font-size: 12px;
|
47
|
+
margin: -7px;
|
48
|
+
margin-bottom: 0px;
|
49
|
+
background-color: #c00;
|
50
|
+
color: #fff;
|
51
|
+
}
|
52
|
+
|
53
|
+
#error_explanation ul li {
|
54
|
+
font-size: 12px;
|
55
|
+
list-style: square;
|
56
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class ApplicationController < ActionController::Base
|
2
|
+
# Prevent CSRF attacks by raising an exception.
|
3
|
+
# For APIs, you may want to use :null_session instead.
|
4
|
+
protect_from_forgery with: :exception
|
5
|
+
prepend_before_filter :set_locale
|
6
|
+
|
7
|
+
private
|
8
|
+
def set_locale
|
9
|
+
if I18n.available_locales.map(&:to_s).include?(params[:locale])
|
10
|
+
I18n.locale = params[:locale]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|