Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
6716e4bc
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
6716e4bc
编写于
1月 03, 2010
作者:
J
José Valim
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Use regexp in lookups instead of traversing namespaces. This removes the need of special cases.
上级
00f3f6dc
变更
3
显示空白变更内容
内联
并排
Showing
3 changed file
with
97 addition
and
128 deletion
+97
-128
railties/lib/rails/generators.rb
railties/lib/rails/generators.rb
+56
-92
railties/lib/rails/generators/base.rb
railties/lib/rails/generators/base.rb
+32
-28
railties/test/generators_test.rb
railties/test/generators_test.rb
+9
-8
未找到文件。
railties/lib/rails/generators.rb
浏览文件 @
6716e4bc
...
...
@@ -117,11 +117,15 @@ def self.fallbacks
end
# Remove the color from output.
#
def
self
.
no_color!
Thor
::
Base
.
shell
=
Thor
::
Shell
::
Basic
end
# Track all generators subclasses.
def
self
.
subclasses
@subclasses
||=
[]
end
# Generators load paths used on lookup. The lookup happens as:
#
# 1) lib generators
...
...
@@ -147,18 +151,10 @@ def self.load_paths
end
load_paths
# Cache load paths. Needed to avoid __FILE__ pointing to wrong paths.
# Rails finds namespaces exactly as thor, with three conveniences:
#
# 1) If your generator name ends with generator, as WebratGenerator, it sets
# its namespace to "webrat", so it can be invoked as "webrat" and not
# "webrat_generator";
#
# 2) If your generator has a generators namespace, as Rails::Generators::WebratGenerator,
# the namespace is set to "rails:generators:webrat", but Rails allows it
# to be invoked simply as "rails:webrat". The "generators" is added
# automatically when doing the lookup;
# Rails finds namespaces similar to thor, it only adds one rule:
#
# 3) Rails looks in load paths and loads the generator just before it's going to be used.
# Generators names must end with "_generator.rb". This is required because Rails
# looks in load paths and loads the generator just before it's going to be used.
#
# ==== Examples
#
...
...
@@ -166,113 +162,81 @@ def self.load_paths
#
# Will search for the following generators:
#
# "rails:
generators:webrat", "webrat:generators
:integration", "webrat"
# "rails:
webrat", "webrat
:integration", "webrat"
#
# On the other hand, if "rails:webrat" is given, it will search for:
#
# "rails:generators:webrat", "rails:webrat"
#
# Notice that the "generators" namespace is handled automatically by Rails,
# so you don't need to type it when you want to invoke a generator in specific.
# Notice that "rails:generators:webrat" could be loaded as well, what
# Rails looks for is the first and last parts of the namespace.
#
def
self
.
find_by_namespace
(
name
,
base
=
nil
,
context
=
nil
)
#:nodoc:
name
,
attempts
=
name
.
to_s
,
[
]
case
name
.
count
(
':'
)
when
1
base
,
name
=
name
.
split
(
':'
)
return
find_by_namespace
(
name
,
base
)
when
0
attempts
+=
generator_names
(
base
,
name
)
if
base
attempts
+=
generator_names
(
name
,
context
)
if
context
end
attempts
<<
name
attempts
+=
generator_names
(
name
,
name
)
unless
name
.
include?
(
?:
)
attempts
.
uniq!
unloaded
=
attempts
-
namespaces
lookup
(
unloaded
)
# Mount regexps to lookup
regexps
=
[]
regexps
<<
/^
#{
base
}
:[\w:]*
#{
name
}
$/
if
base
regexps
<<
/^
#{
name
}
:[\w:]*
#{
context
}
$/
if
context
regexps
<<
/^[(
#{
name
}
):]+$/
regexps
.
uniq!
# Check if generator happens to be loaded
checked
=
subclasses
.
dup
klass
=
find_by_regexps
(
regexps
,
checked
)
return
klass
if
klass
attempts
.
each
do
|
namespace
|
klass
=
Thor
::
Util
.
find_by_namespace
(
namespace
)
# Try to require other generators by looking in load_paths
lookup
(
name
,
context
)
unchecked
=
subclasses
-
checked
klass
=
find_by_regexps
(
regexps
,
unchecked
)
return
klass
if
klass
end
# Invoke fallbacks
invoke_fallbacks_for
(
name
,
base
)
||
invoke_fallbacks_for
(
context
,
name
)
end
# Tries to find a generator which the namespace match the regexp.
def
self
.
find_by_regexps
(
regexps
,
klasses
)
klasses
.
find
do
|
klass
|
namespace
=
klass
.
namespace
regexps
.
find
{
|
r
|
namespace
=~
r
}
end
end
# Receives a namespace, arguments and the behavior to invoke the generator.
# It's used as the default entry point for generate, destroy and update
# commands.
#
def
self
.
invoke
(
namespace
,
args
=
ARGV
,
config
=
{})
if
klass
=
find_by_namespace
(
namespace
,
"rails"
)
names
=
namespace
.
to_s
.
split
(
':'
)
if
klass
=
find_by_namespace
(
names
.
pop
,
names
.
shift
||
"rails"
)
args
<<
"--help"
if
klass
.
arguments
.
any?
{
|
a
|
a
.
required?
}
&&
args
.
empty?
klass
.
start
args
,
config
klass
.
start
(
args
,
config
)
else
puts
"Could not find generator
#{
namespace
}
."
end
end
# Show help message with available generators.
#
def
self
.
help
rails
=
Rails
::
Generators
.
builtin
.
map
do
|
group
,
name
|
name
if
group
==
"rails"
end
rails
.
compact!
rails
.
sort!
puts
"Please select a generator."
puts
"Builtin:
#{
rails
.
join
(
', '
)
}
."
# Load paths and remove builtin
paths
,
others
=
load_paths
.
dup
,
[]
paths
.
pop
paths
.
each
do
|
path
|
tail
=
[
"*"
,
"*"
,
"*_generator.rb"
]
until
tail
.
empty?
others
+=
Dir
[
File
.
join
(
path
,
*
tail
)].
collect
do
|
file
|
name
=
file
.
split
(
'/'
)[
-
tail
.
size
,
2
]
name
.
last
.
sub!
(
/_generator\.rb$/
,
''
)
name
.
uniq!
name
.
join
(
':'
)
end
tail
.
shift
end
end
builtin
=
Rails
::
Generators
.
builtin
.
each
{
|
n
|
n
.
sub!
(
/^rails:/
,
''
)
}
builtin
.
sort!
lookup
(
"*"
)
others
=
subclasses
.
map
{
|
k
|
k
.
namespace
.
gsub
(
':generators:'
,
':'
)
}
others
-=
Rails
::
Generators
.
builtin
others
.
sort!
puts
"Please select a generator."
puts
"Builtin:
#{
builtin
.
join
(
', '
)
}
."
puts
"Others:
#{
others
.
join
(
', '
)
}
."
unless
others
.
empty?
end
protected
# Return all defined namespaces.
#
def
self
.
namespaces
#:nodoc:
Thor
::
Base
.
subclasses
.
map
{
|
klass
|
klass
.
namespace
}
end
# Keep builtin generators in an Array[Array[group, name]].
#
# Keep builtin generators in an Array.
def
self
.
builtin
#:nodoc:
Dir
[
File
.
dirname
(
__FILE__
)
+
'/generators/*/*'
].
collect
do
|
file
|
file
.
split
(
'/'
)[
-
2
,
2
]
file
.
split
(
'/'
)[
-
2
,
2
]
.
join
(
':'
)
end
end
# By default, Rails strips the generator namespace to make invocations
# easier. This method generaters the both possibilities names.
def
self
.
generator_names
(
first
,
second
)
#:nodoc:
[
"
#{
first
}
:generators:
#{
second
}
"
,
"
#{
first
}
:
#{
second
}
"
]
end
# Try callbacks for the given base.
#
# Try fallbacks for the given base.
def
self
.
invoke_fallbacks_for
(
name
,
base
)
#:nodoc:
return
nil
unless
base
&&
fallbacks
[
base
.
to_sym
]
invoked_fallbacks
=
[]
...
...
@@ -290,10 +254,10 @@ def self.invoke_fallbacks_for(name, base) #:nodoc:
# Receives namespaces in an array and tries to find matching generators
# in the load path.
#
def
self
.
lookup
(
attempts
)
#:nodoc:
attempts
=
attempts
.
map
{
|
a
|
"
#{
a
.
split
(
":"
).
last
}
_generator"
}.
uniq
attempts
=
"{
#{
attempts
.
join
(
','
)
}
}.rb"
def
self
.
lookup
(
*
attempts
)
#:nodoc:
attempts
.
compact!
attempts
.
uniq!
attempts
=
"{
#{
attempts
.
join
(
','
)
}
}
_generator
.rb"
self
.
load_paths
.
each
do
|
path
|
Dir
[
File
.
join
(
path
,
'**'
,
attempts
)].
each
do
|
file
|
...
...
railties/lib/rails/generators/base.rb
浏览文件 @
6716e4bc
...
...
@@ -76,17 +76,18 @@ def self.namespace(name=nil)
#
# The controller generator will then try to invoke the following generators:
#
# "rails:
generators:test_unit", "test_unit:generators
:controller", "test_unit"
# "rails:
test_unit", "test_unit
:controller", "test_unit"
#
# In this case, the "test_unit:generators:controller" is available and is
# invoked. This allows any test framework to hook into Rails as long as it
# provides any of the hooks above.
# Notice that "rails:generators:test_unit" could be loaded as well, what
# Rails looks for is the first and last parts of the namespace. This is what
# allows any test framework to hook into Rails as long as it provides any
# of the hooks above.
#
# ==== Options
#
# Th
is lookup can be customized with two options: :base and :as. The first
#
is the root module value and in the example above defaults to "rails"
.
# Th
e later defaults to the generator name, without the "Generator" ending
.
# Th
e first and last part used to find the generator to be invoked are
#
guessed based on class invokes hook_for, as noticed in the example above
.
# Th
is can be customized with two options: :base and :as
.
#
# Let's suppose you are creating a generator that needs to invoke the
# controller generator from test unit. Your first attempt is:
...
...
@@ -97,7 +98,7 @@ def self.namespace(name=nil)
#
# The lookup in this case for test_unit as input is:
#
# "test_unit:
generators:
awesome", "test_unit"
# "test_unit:awesome", "test_unit"
#
# Which is not the desired the lookup. You can change it by providing the
# :as option:
...
...
@@ -108,18 +109,18 @@ def self.namespace(name=nil)
#
# And now it will lookup at:
#
# "test_unit:
generators:awesome
", "test_unit"
# "test_unit:
controller
", "test_unit"
#
# Similarly, if you want it to also lookup in the rails namespace, you just
# need to provide the :base value:
#
# class AwesomeGenerator < Rails::Generators::Base
# hook_for :test_framework, :
base
=> :rails, :as => :controller
# hook_for :test_framework, :
in
=> :rails, :as => :controller
# end
#
# And the lookup is exactly the same as previously:
#
# "rails:
generators:test_unit", "test_unit:generators
:controller", "test_unit"
# "rails:
test_unit", "test_unit
:controller", "test_unit"
#
# ==== Switches
#
...
...
@@ -151,11 +152,11 @@ def self.namespace(name=nil)
# ==== Custom invocations
#
# You can also supply a block to hook_for to customize how the hook is
# going to be invoked. The block receives two
parameter
s, an instance
# going to be invoked. The block receives two
argument
s, an instance
# of the current class and the klass to be invoked.
#
# For example, in the resource generator, the controller should be invoked
# with a pluralized class name. B
y default,
it is invoked with the same
# with a pluralized class name. B
ut by default
it is invoked with the same
# name as the resource generator, which is singular. To change this, we
# can give a block to customize how the controller can be invoked.
#
...
...
@@ -178,11 +179,11 @@ def self.hook_for(*names, &block)
end
unless
class_options
.
key?
(
name
)
class_option
name
,
defaults
.
merge!
(
options
)
class_option
(
name
,
defaults
.
merge!
(
options
)
)
end
hooks
[
name
]
=
[
in_base
,
as_hook
]
invoke_from_option
name
,
options
,
&
block
invoke_from_option
(
name
,
options
,
&
block
)
end
end
...
...
@@ -193,7 +194,7 @@ def self.hook_for(*names, &block)
# remove_hook_for :orm
#
def
self
.
remove_hook_for
(
*
names
)
remove_invocation
*
names
remove_invocation
(
*
names
)
names
.
each
do
|
name
|
hooks
.
delete
(
name
)
...
...
@@ -219,7 +220,10 @@ def self.inherited(base) #:nodoc:
# and can point to wrong directions when inside an specified directory.
base
.
source_root
if
base
.
name
&&
base
.
name
!~
/Base$/
&&
base
.
base_name
&&
base
.
generator_name
&&
defined?
(
Rails
.
root
)
&&
Rails
.
root
if
base
.
name
&&
base
.
name
!~
/Base$/
Rails
::
Generators
.
subclasses
<<
base
if
defined?
(
Rails
.
root
)
&&
Rails
.
root
path
=
File
.
expand_path
(
File
.
join
(
Rails
.
root
,
'lib'
,
'templates'
))
if
base
.
name
.
include?
(
'::'
)
base
.
source_paths
<<
File
.
join
(
path
,
base
.
base_name
,
base
.
generator_name
)
...
...
@@ -228,6 +232,7 @@ def self.inherited(base) #:nodoc:
end
end
end
end
protected
...
...
@@ -290,12 +295,10 @@ def self.base_name
# Rails::Generators::MetalGenerator will return "metal" as generator name.
#
def
self
.
generator_name
if
name
@generator_name
||=
begin
if
klass_name
=
name
.
to_s
.
split
(
'::'
).
last
klass_name
.
sub!
(
/Generator$/
,
''
)
klass_name
.
underscore
end
if
generator
=
name
.
to_s
.
split
(
'::'
).
last
generator
.
sub!
(
/Generator$/
,
''
)
generator
.
underscore
end
end
end
...
...
@@ -339,6 +342,7 @@ def self.hooks #:nodoc:
#
def
self
.
prepare_for_invocation
(
name
,
value
)
#:nodoc:
if
value
&&
constants
=
self
.
hooks
[
name
]
value
=
name
if
TrueClass
===
value
Rails
::
Generators
.
find_by_namespace
(
value
,
*
constants
)
else
super
...
...
railties/test/generators_test.rb
浏览文件 @
6716e4bc
...
...
@@ -9,6 +9,11 @@ def setup
Gem
.
stubs
(
:respond_to?
).
with
(
:loaded_specs
).
returns
(
false
)
end
def
test_invoke_add_generators_to_raw_lookups
TestUnit
::
Generators
::
ModelGenerator
.
expects
(
:start
).
with
([
"Account"
],
{})
Rails
::
Generators
.
invoke
(
"test_unit:model"
,
[
"Account"
])
end
def
test_invoke_when_generator_is_not_found
output
=
capture
(
:stdout
){
Rails
::
Generators
.
invoke
:unknown
}
assert_equal
"Could not find generator unknown.
\n
"
,
output
...
...
@@ -51,12 +56,6 @@ def test_find_by_namespace_with_duplicated_name
assert_equal
"foobar:foobar"
,
klass
.
namespace
end
def
test_find_by_namespace_add_generators_to_raw_lookups
klass
=
Rails
::
Generators
.
find_by_namespace
(
"test_unit:model"
)
assert
klass
assert_equal
"test_unit:generators:model"
,
klass
.
namespace
end
def
test_find_by_namespace_lookup_to_the_rails_root_folder
klass
=
Rails
::
Generators
.
find_by_namespace
(
:fixjour
)
assert
klass
...
...
@@ -96,7 +95,7 @@ def test_find_by_namespace_lookup_with_gem_specification
end
def
test_builtin_generators
assert
Rails
::
Generators
.
builtin
.
include?
%w(rails model
)
assert
Rails
::
Generators
.
builtin
.
include?
(
"rails:model"
)
end
def
test_rails_generators_help_with_builtin_information
...
...
@@ -107,7 +106,7 @@ def test_rails_generators_help_with_builtin_information
def
test_rails_generators_with_others_information
output
=
capture
(
:stdout
){
Rails
::
Generators
.
help
}.
split
(
"
\n
"
).
last
assert_equal
"Others: active_record:fixjour, fixjour, foobar
, mspec, rails:javascripts
."
,
output
assert_equal
"Others: active_record:fixjour, fixjour, foobar
:foobar, mspec, rails:javascripts, xspec
."
,
output
end
def
test_warning_is_shown_if_generator_cant_be_loaded
...
...
@@ -178,6 +177,8 @@ def self.name() 'NewGenerator' end
end
assert_equal
false
,
klass
.
class_options
[
:generate
].
default
ensure
Rails
::
Generators
.
subclasses
.
delete
(
klass
)
end
def
test_source_paths_for_not_namespaced_generators
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录