环境:mac os x lion
homebrew是用ruby写的脚本,发现和rvm极其相似
安装 homebrew
>/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"
安装imagemagick
>brew install imagemagick
安装到libtiff 库时 出错
curl: (7) couldn't connect to host Error: Failure while executing: /usr/bin/curl -f#LA Homebrew\ 0.8\ (Ruby\ 1.8.7-249;\ Mac\ OS\ X\ 10.7.1) ftp://ftp.remotesensing.org/pub/libtiff/tiff-3.9.5.zip -o /Users/wangxianfeng/Library/Caches/Homebrew/libtiff-3.9.5.zip
fixed :
>/usr/bin/curl http://download2.osgeo.org/libtiff/tiff-3.9.5.zip -o ~/Library/Caches/Homebrew/libtiff-3.9.5.zip
再次安装:
>brew install imagemagick
最后测试安装成功:
wxianfeng:inono wangxianfeng$ convert --version Version: ImageMagick 6.7.1-1 2011-09-10 Q16 http://www.imagemagick.org Copyright: Copyright (C) 1999-2011 ImageMagick Studio LLC Features: OpenMP
可以查看出brew安装了下面的库:
wxianfeng:inono wangxianfeng$ brew list imagemagick jasper jpeg libtiff little-cms
see:
https://github.com/mxcl/homebrew/wiki/installation
https://github.com/mxcl/homebrew/pull/5168
时间: 2011-07-24
收获:
发现北京ROR的公司不是一般的多,签到单上看到N多公司,技术上没有太大收获,都是介绍性的,没有实战性的,内容主要涉及: mirah , Mongodb,Erlang,Grape
进程:http://www.surveymonkey.com/s/MSY2L7T
PS : 798 很好玩,很有艺术特色
现场:
798 入口
Ruby活动地方
Rails rumble 创始人
现场job board
现场
清一色老外,清一色Mac
介绍Mirah
798
798
798
yaml 的语法真是变态 , 表示个数组这么麻烦, 更复杂的数据结构 那不是更麻烦 !!!
yaml 文件:
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html one: name: MyString orgunit_id: 1 inheritable: false # codes 是yaml数组表示方法 # 缩进只能是两个空格为一级,不能是其他字符 codes: - 1 - a - 2 - b - 3 - c
ruby 解析yaml:
ruby-1.9.2-p0 > file = "#{Rails.root}/test/fixtures/enumerations.yml" => "/usr/local/system/projects/entos/ent_os/test/fixtures/enumerations.yml" ruby-1.9.2-p0 > YAML.load File.read(file) => {"one"=>{"name"=>"MyString", "orgunit_id"=>1, "inheritable"=>false, "codes"=>[1, "a", 2, "b", 3, "c"]}}
不知道怎么写的可以 使用 to_yaml 方法 看一下:
irb(main):001:0> => {"one"=>{"name"=>"MyString", "inheritable"=>false, "orgunit_id"=>1, "codes"=>[1, "a", 2, "b", 3, "c"]}} irb(main):002:0> require "yaml" => true irb(main):003:0> hsh.to_yaml => "--- \none: \n name: MyString\n inheritable: false\n orgunit_id: 1\n codes: \n - 1\n - a\n - 2\n - b\n - 3\n - c\n"
可读性 更好的 使用 y 方法
ruby-1.9.2-p0 > y hsh --- one: name: MyString orgunit_id: 1 inheritable: false codes: - 1 - a - 2 - b - 3 - c => nil
环境:ruby 1.9.2 + rake 0.8.7 + rails 3.0.3
今天在写 rake 文件 , 提示我没找到 model Class,问题在于我没加 => :environment , 那为什么加上 => :environment 就可以了 , 研究了下rake:
task :test => :environment do end
其中后面的 :environment 也是 一个 task , 也就是说在执行 test 这个 task 之前 会执行 :environment 这个 task,有点像rails controller 中的 before_filter ,那么 :environment 这个task 定义在什么地方,rails project中也没有啊 。。。,定义在 rails 源码中了 ,你在 你的project下执行 rake environment 不会报错的
wxianfeng@ubuntu:/usr/local/system/projects/entos/ent_os$ rake environment --trace (in /usr/local/system/projects/entos/ent_os) ** Invoke environment (first_time) ** Execute environment
不过 也看不到 输出什么信息,因为只是加载了 运行环境而已 ,那么从哪里执行的,定义在 project 下 Rakefile 中了
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
require 'rake'
EntOs::Application.load_tasks继续跟踪 load_tasks:
最后 找到了 task environment
def initialize_tasks
require "rails/tasks"
task :environment do
$rails_rake_task = true
require_environment!
end
end
全部文件 here
所以加载了 environment 也就可以 找到 model Class 了
总结:
1,rake 命名格式
rakefile, Rakefile, rakefile.rb, Rakefile.rb 都可以 ,常用 Rakefile
另外 rails 中使用的话,还可以 使用 .rake 后缀的文件
2,设置命名空间
namespace :test do end
3,设置默认task
task :default => ["test"]
可以指定多个 task,执行 rake 后 ,默认调用的是 default task
4,指定task执行顺序
task :test => [:hello,:world]
5,查看rake 任务
rake -T rake --tasks rake -T db: # 查看db打头的task
6,跟踪task
rake test --trace
更多 options
wxianfeng@ubuntu:/usr/local/system/projects/entos/ent_os$ rake -h rake [-f rakefile] {options} targets... Options are ... -C, --classic-namespace Put Task and FileTask in the top level namespace -D, --describe [PATTERN] Describe the tasks (matching optional PATTERN), then exit. -n, --dry-run Do a dry run without executing actions. -e, --execute CODE Execute some Ruby code and exit. -p, --execute-print CODE Execute some Ruby code, print the result, then exit. -E, --execute-continue CODE Execute some Ruby code, then continue with normal task processing. -I, --libdir LIBDIR Include LIBDIR in the search path for required modules. -P, --prereqs Display the tasks and dependencies, then exit. -q, --quiet Do not log messages to standard output. -f, --rakefile [FILE] Use FILE as the rakefile. -R, --rakelibdir RAKELIBDIR, Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib') --rakelib -r, --require MODULE Require MODULE before executing rakefile. --rules Trace the rules resolution. -N, --no-search, --nosearch Do not search parent directories for the Rakefile. -s, --silent Like --quiet, but also suppresses the 'in directory' announcement. -g, --system Using system wide (global) rakefiles (usually '~/.rake/*.rake'). -G, --no-system, --nosystem Use standard project Rakefile search paths, ignore system wide rakefiles. -T, --tasks [PATTERN] Display the tasks (matching optional PATTERN) with descriptions, then exit. -t, --trace Turn on invoke/execute tracing, enable full backtrace. -v, --verbose Log message to standard output. -V, --version Display the program version. -h, -H, --help Display this help message.
DEMO:
wxianfeng@ubuntu:~/test/rake$ cat Rakefile desc "Default: test" task :default => ["r:test"] namespace :r do desc "test" task :test do puts "test" end desc "test1" task :test1 => :test do puts "test1" end desc "test3" task :test3 => :test4 do puts "test3" end end
SEE:
http://hi.baidu.com/%D0%C7203/blog/item/ebda2dd09f1d698ea1ec9c7a.html
http://guides.rubyonrails.org/command_line.html
http://ericzouthoughts.wordpress.com/2009/06/20/execute-shell-command-in-ruby-rake-task/
今天在rails中使用 returning 的时候 log 打出warning:
Object#returning has been deprecated in favor of Object#tap
环境是 ruby 1.9.2 + rails 3.0.3
从warn上看是returning不建议使用,建议使用tap方法,那么tap方法和returning方法有什么不同
Object#tap 方法是 ruby1.8.7 以后加入的,Object#returning 方法是 rails添加的
rails 3.0.3 returning 源码:here
rails 2.3.5 returning源码:
class Object
# Returns +value+ after yielding +value+ to the block. This simplifies the
# process of constructing an object, performing work on the object, and then
# returning the object from a method. It is a Ruby-ized realization of the K
# combinator, courtesy of Mikael Brockman.
#
# ==== Examples
#
# # Without returning
# def foo
# values = []
# values << "bar"
# values << "baz"
# return values
# end
#
# foo # => ['bar', 'baz']
#
# # returning with a local variable
# def foo
# returning values = [] do
# values << 'bar'
# values << 'baz'
# end
# end
#
# foo # => ['bar', 'baz']
#
# # returning with a block argument
# def foo
# returning [] do |values|
# values << 'bar'
# values << 'baz'
# end
# end
#
# foo # => ['bar', 'baz']
def returning(value)
yield(value)
value
end
# Yields <code>x</code> to the block, and then returns <code>x</code>.
# The primary purpose of this method is to "tap into" a method chain,
# in order to perform operations on intermediate results within the chain.
#
# (1..10).tap { |x| puts "original: #{x.inspect}" }.to_a.
# tap { |x| puts "array: #{x.inspect}" }.
# select { |x| x%2 == 0 }.
# tap { |x| puts "evens: #{x.inspect}" }.
# map { |x| x*x }.
# tap { |x| puts "squares: #{x.inspect}" }
def tap
yield self
self
end unless Object.respond_to?(:tap)
# An elegant way to factor duplication out of options passed to a series of
# method calls. Each method called in the block, with the block variable as
# the receiver, will have its options merged with the default +options+ hash
# provided. Each method called on the block variable must take an options
# hash as its final argument.
#
# with_options :order => 'created_at', :class_name => 'Comment' do |post|
# post.has_many :comments, :conditions => ['approved = ?', true], :dependent => :delete_all
# post.has_many :unapproved_comments, :conditions => ['approved = ?', false]
# post.has_many :all_comments
# end
#
# Can also be used with an explicit receiver:
#
# map.with_options :controller => "people" do |people|
# people.connect "/people", :action => "index"
# people.connect "/people/:id", :action => "show"
# end
#
def with_options(options)
yield ActiveSupport::OptionMerger.new(self, options)
end
# A duck-type assistant method. For example, Active Support extends Date
# to define an acts_like_date? method, and extends Time to define
# acts_like_time?. As a result, we can do "x.acts_like?(:time)" and
# "x.acts_like?(:date)" to do duck-type-safe comparisons, since classes that
# we want to act like Time simply need to define an acts_like_time? method.
def acts_like?(duck)
respond_to? "acts_like_#{duck}?"
end
end
可以看到 tap 方法也封装了,为了防止 ruby版本过低 没有tap方法就 添加Object#tap 方法,tap 和 returning本质是一样的,函数体都是调用block闭包,只不过returning需要传递一个参数给闭包,最后返回的就是这个参数,而 tap直接操作self指针,最后返回的也就是self
另外最新rails源码(>rails3.0.3)已经没有 returning方法了,所以以后最好都用tap方法
DEMO1:
require "rubygems" require "active_support" # Object#tap 是>ruby1.8.7 有的 # Object#returning 是Rails 封装的方法, rails3.X 已经不建议使用 # Object#tap 可以支持链式(chain)操作 (1..10).tap { |x| puts "original: #{x.inspect}" }.to_a.tap { |x| puts "array: #{x.inspect}" }.select {|x| x%2==0}.tap { |x| puts "evens: #{x.inspect}" }.map {|x| x*x}.tap { |x| puts "squares: #{x.inspect}" } def object_tap {}.tap do |h| # => Hash.new.tap h[:a] = 1 h[:b] =2 end end p object_tap # {:b=>2, :a=>1} def object_returning returning Hash.new do |h| # 注意这里不能用 {} , 放在 returning 方法后面 当作成 block闭包了 h[:a] = 1 h[:b] = 2 end end p object_returning # {:b=>2, :a=>1}
DEMO2:
require "rubygems" require "active_support" class Hash def shift_value_tap_self self.tap do |h| h.each { |k,v| v.shift if v.is_a?(Array) } end end def shift_value_tap {}.tap do |h| self.each { |k,v| v.is_a?(Array) ? h[k] = v.shift : h[k] = v } end end def shift_value_returning returning Hash.new do |h| self.each { |k,v| v.is_a?(Array) ? h[k] = v.shift : h[k] = v } end end def shift_value_returning_self returning self do |h| h.each { |k,v| v.shift if v.is_a?(Array) } end end end hsh = {"a"=>[1,2,3],"b"=>["g","f","w"],"c"=>"fuck_china"} hsh1 = {"a"=>[1,2,3],"b"=>["g","f","w"],"c"=>"fuck_china"} hsh2 = {"a"=>[1,2,3],"b"=>["g","f","w"],"c"=>"fuck_china"} hsh3 = {"a"=>[1,2,3],"b"=>["g","f","w"],"c"=>"fuck_china"} p hsh.shift_value_tap # {"a"=>1, "b"=>"g", "c"=>"fuck_china"} p hsh1.shift_value_returning # {"a"=>1, "b"=>"g", "c"=>"fuck_china"} p hsh2.shift_value_tap_self # {"a"=>[2, 3], "b"=>["f", "w"], "c"=>"fuck_china"} p hsh3.shift_value_returning_self # {"a"=>[2, 3], "b"=>["f", "w"], "c"=>"fuck_china"}
SEE:
http://blog.rubybestpractices.com/posts/gregory/011-tap-that-hash.html
http://www.simonecarletti.com/blog/2010/09/rails-3-beware-the-tap-pattern/
http://fuliang.javaeye.com/blog/857163
环境:ruby 1.9.2
有这样一个需求, 给你 任意一个字符串,把它转化为类,网上大多数的 解决办法是 下面三种:
Kernel.const_get(:User) # Object.const_get(:User) eval(’User’) ‘User’.constantize
但是上面三种方法, 这个 User 事先必须是初始化的,不然会报错,如下:
Object.const_get(:User) # uninitialized constant User (NameError)
所以需要加个判断 这个 Class 有没有初始化,没有的话 再set 一个Class
require "rails/all" def Kernel.const_missing(name) Object.const_set(name,Class.new) end #p Kernel.const_get("baoxiaos".to_sym) # wrong constant name baoxiaos (NameError) p Kernel.const_get("baoxiaos".classify.to_sym) # Baoxiao , const的首字母必须大写 p Kernel.constants # [] p Object.constants.include?(:UBaoxiao) # true
刚开始把这个 const 定义在 Object 里:
require "rails/all" def Object.const_missing(name) Object.const_set(name,Class.new) end #p Object.const_get("baoxiaos".to_sym) # wrong constant name baoxiaos (NameError) p Object.const_get("baoxiaos".classify.to_sym)
发现 用在 rails 中后 , rails 处处报错,可能 怪我重写了 Object.const_missing 导致的 ……..
上面方法的原理是 当找不到 const的时候 执行了
Object.const_set(name,Class.new)
那么 name 就变成是 Class 的实例了 , 为什么定义在 Kernel 中的 const_missing ,Object 也可以访问到,需要注意 Object,Kernel 之间的关系,Object 是 inluce Kernel 的,如下:
class Object include Kernel end
SEE:
http://niczsoft.com/2010/01/string-to-class-in-ruby-on-rails/
http://www.ruby-forum.com/topic/96222
环境:ruby 1.9.2 + ubuntu 10.10
instance_variables 得到当前 对象已经开辟内存空间的实例变量,疑惑在这里
class Foo attr_accessor :sex,:birthday end p Foo.new.instance_variables # => []
刚开始不理解,怎么是 空……..
后来想了想,因为 ruby 是 动态的解释型的语言,如果没有 给实例变量赋值 的话,是不会开辟内存空间的,所以 instance_variables 只能得到已经开辟内存空间的 实例变量,
但是如果是 编译型的静态语言 则不然,例如java ,实例变量 声明了 就会开辟内存空间了
DEMO1:
# ruby version : 1.9.2 class Foo attr_accessor :sex,:birthday # attr_accessor ruby里封装的method end p Foo.new.instance_variables # => [] f = Foo.new p f.sex #=> nil f.sex = 'M' p f.instance_variables #=> [:@sex] p f.inspect # => "#<Foo:0x85ead8c @sex=\"M\">" b = Foo.new b.birthday = nil # 注意赋值为nil,也开辟了内存空间 p b.instance_variables # => [:@birthday] p b.inspect # => "#<Foo:0x9dca358 @birthday=nil>"
DEMO2:
class Foo def initialize @name = 'wxianfeng' end def bar # => as getter method @name end end f = Foo.new p f.instance_variables #=> [:@name] p f.inspect #=> "#<Foo:0x8aa7c08 @name=\"wxianfeng\">" p f.name # => undefined method `name' for #<Foo:0x99adf7c @name="wxianfeng"> p f.bar # => "wxianfeng"
ruby 源码:
# obj.instance_variables => array
#
#
# Returns an array of instance variable names for the receiver. Note
# that simply defining an accessor does not create the corresponding
# instance variable.
#
# class Fred
# attr_accessor :a1
# def initialize
# @iv = 3
# end
# end
# Fred.new.instance_variables #=> ["@iv"]
#
#
def instance_variables
# This is just a stub for a builtin Ruby method.
# See the top of this file for more info.
end
SEE:
http://www.megasolutions.net/ruby/instance_variables-doesnt-return-unassigned-variables-68358.aspx
环境:ruby 1.9
\1 和 $1 在用 ruby 正则的时候 经常会用到 , 那么有什么区别呢,今天 来梳理一下:
\1 : 是 向后引用 , 常使用在 sub , gsub 中
$1 : 是 ruby 里的全局变量
看几个demo:
demo:
"ab12cd12".gsub(/(\d+)cd(\1)/,"") # => "ab" 这个正则就相当于 /(\d+)cd12/ ,因为 \1 引用的是 前面的 (\d+) ,而前面的 (\d+) 匹配出来的结果是 12 "ab12cd".gsub(/(\d+)/,'34\1') # => "ab3412cd"
p "ab12cd".gsub(/(\d+)/,'34\1') # "ab3412cd" p $1 # "12" p "ab56cd".gsub(/(\d+)/,"78#{$1}") # "ab7812cd" , 这个时候的 $1 为 上面的 12
p "ab12cd".gsub(/(\d+)/,'34\1') # "ab3412cd" p $1 # "12" str = "ab56cd".gsub(/(\d+)/) do |ele| "78#{$1}" # 这里的 $1 是 56 end p str # "ab7856cd"
p "ab56cd".gsub(/(\d+)/,"78#{$1}") # "ab78cd" 这里的 $1 是 nil
str = "ab56cd".gsub(/(\d+)/) do |ele| "78#{$1}" end p str # "ab7856cd"
得出结论:
1,\1 和 $1 是两个 不同的用法
2,特别注意 $1 在 gsub中 block 中,和 写在replacement 中 是不一样的 , \1 用在 replacement 中 ,$1 用在 block 中 ,这个源码中已经说明了
3,\1 必须用单引号
看下源码中的解释:
# str.gsub(pattern, replacement) => new_str # str.gsub(pattern) {|match| block } => new_str # # # Returns a copy of <i>str</i> with <em>all</em> occurrences of <i>pattern</i> # replaced with either <i>replacement</i> or the value of the block. The # <i>pattern</i> will typically be a <code>Regexp</code>; if it is a # <code>String</code> then no regular expression metacharacters will be # interpreted (that is <code>/\d/</code> will match a digit, but # <code>'\d'</code> will match a backslash followed by a 'd'). # # If a string is used as the replacement, special variables from the match # (such as <code>$&</code> and <code>$1</code>) cannot be substituted into it, # as substitution into the string occurs before the pattern match # starts. However, the sequences <code>\1</code>, <code>\2</code>, and so on # may be used to interpolate successive groups in the match. # # In the block form, the current match string is passed in as a parameter, and # variables such as <code>$1</code>, <code>$2</code>, <code>$`</code>, # <code>$&</code>, and <code>$'</code> will be set appropriately. The value # returned by the block will be substituted for the match on each call. # # The result inherits any tainting in the original string or any supplied # replacement string. # # "hello".gsub(/[aeiou]/, '*') #=> "h*ll*" # "hello".gsub(/([aeiou])/, '<\1>') #=> "h<e>ll<o>" # "hello".gsub(/./) {|s| s[0].to_s + ' '} #=> "104 101 108 108 111 " # # def gsub(pattern, replacement) # This is just a stub for a builtin Ruby method. # See the top of this file for more info. end
replacement 时:
# If a string is used as the replacement, special variables from the match
# (such as <code>$&</code> and <code>$1</code>) cannot be substituted into it,
# as substitution into the string occurs before the pattern match
# starts. However, the sequences <code>\1</code>, <code>\2</code>, and so on
# may be used to interpolate successive groups in the match.
block 时:
# In the block form, the current match string is passed in as a parameter, and
# variables such as <code>$1</code>, <code>$2</code>, <code>$`</code>,
# <code>$&</code>, and <code>$’</code> will be set appropriately. The value
# returned by the block will be substituted for the match on each call.
环境:ruby 1.9.2 + ubuntu 10.10 + rails 3.0.3
我们知道 ruby 中 扩展class ,写公用方法 ,或者 利用命名空间 来模块化 ,都是通过 module 来实现的 , 今天 看 rails 中 camelize 方法的源码的时候 , 发现 module 这样写的…..
active_support/inflector/methods.rb
module ActiveSupport # The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without, # and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept # in inflections.rb. # # The Rails core team has stated patches for the inflections library will not be accepted # in order to avoid breaking legacy applications which may be relying on errant inflections. # If you discover an incorrect inflection and require it for your application, you'll need # to correct it yourself (explained below). module Inflector extend self # By default, +camelize+ converts strings to UpperCamelCase. If the argument to +camelize+ # is set to <tt>:lower</tt> then +camelize+ produces lowerCamelCase. # # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces. # # Examples: # "active_record".camelize # => "ActiveRecord" # "active_record".camelize(:lower) # => "activeRecord" # "active_record/errors".camelize # => "ActiveRecord::Errors" # "active_record/errors".camelize(:lower) # => "activeRecord::Errors" # # As a rule of thumb you can think of +camelize+ as the inverse of +underscore+, # though there are cases where that does not hold: # # "SSLError".underscore.camelize # => "SslError" def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true) if first_letter_in_uppercase lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } else lower_case_and_underscored_word.to_s[0].chr.downcase + camelize(lower_case_and_underscored_word)[1..-1] end end # Makes an underscored, lowercase form from the expression in the string. # # Changes '::' to '/' to convert namespaces to paths. # # Examples: # "ActiveRecord".underscore # => "active_record" # "ActiveRecord::Errors".underscore # => active_record/errors # # As a rule of thumb you can think of +underscore+ as the inverse of +camelize+, # though there are cases where that does not hold: # # "SSLError".underscore.camelize # => "SslError" def underscore(camel_cased_word) word = camel_cased_word.to_s.dup word.gsub!(/::/, '/') word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') word.gsub!(/([a-z\d])([A-Z])/,'\1_\2') word.tr!("-", "_") word.downcase! word end # Replaces underscores with dashes in the string. # # Example: # "puni_puni" # => "puni-puni" def dasherize(underscored_word) underscored_word.gsub(/_/, '-') end # Removes the module part from the expression in the string. # # Examples: # "ActiveRecord::CoreExtensions::String::Inflections".demodulize # => "Inflections" # "Inflections".demodulize # => "Inflections" def demodulize(class_name_in_module) class_name_in_module.to_s.gsub(/^.*::/, '') end # Creates a foreign key name from a class name. # +separate_class_name_and_id_with_underscore+ sets whether # the method should put '_' between the name and 'id'. # # Examples: # "Message".foreign_key # => "message_id" # "Message".foreign_key(false) # => "messageid" # "Admin::Post".foreign_key # => "post_id" def foreign_key(class_name, separate_class_name_and_id_with_underscore = true) underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id") end # Ruby 1.9 introduces an inherit argument for Module#const_get and # #const_defined? and changes their default behavior. if Module.method(:const_get).arity == 1 # Tries to find a constant with the name specified in the argument string: # # "Module".constantize # => Module # "Test::Unit".constantize # => Test::Unit # # The name is assumed to be the one of a top-level constant, no matter whether # it starts with "::" or not. No lexical context is taken into account: # # C = 'outside' # module M # C = 'inside' # C # => 'inside' # "C".constantize # => 'outside', same as ::C # end # # NameError is raised when the name is not in CamelCase or the constant is # unknown. def constantize(camel_cased_word) names = camel_cased_word.split('::') names.shift if names.empty? || names.first.empty? constant = Object names.each do |name| constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name) end constant end else def constantize(camel_cased_word) #:nodoc: names = camel_cased_word.split('::') names.shift if names.empty? || names.first.empty? constant = Object names.each do |name| constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name) end constant end end # Turns a number into an ordinal string used to denote the position in an # ordered sequence such as 1st, 2nd, 3rd, 4th. # # Examples: # ordinalize(1) # => "1st" # ordinalize(2) # => "2nd" # ordinalize(1002) # => "1002nd" # ordinalize(1003) # => "1003rd" def ordinalize(number) if (11..13).include?(number.to_i % 100) "#{number}th" else case number.to_i % 10 when 1; "#{number}st" when 2; "#{number}nd" when 3; "#{number}rd" else "#{number}th" end end end end end
发现 了这样的写法
module A module B extend self ..... end end
extend self 有何作用?
先来看个demo:
module Foo module Bar extend self # self => Foo::Bar def hello p "hello" end end end class Klass include Foo::Bar end Klass.new.hello # "hello" Foo::Bar.hello # "hello" Klass.hello # undefined method `hello' for Klass:Class (NoMethodError)
发现 module 中的方法 可以当作模块方法 直接被Module调用 , 被include 到class 中后 , 依然还是 class 的实例方法 , 恩,不错,以后 像下面 这样的写法, 都要 改改了:
module A def self.foo end end
改成这样:
module A extend self def foo end end
demo里的extend self 其实就是 Foo::Bar.extend(Foo::Bar)
所以 可以 更动态的 写成这样:
module Foo module Bar def hello p "hello" end end end class Klass include Foo::Bar end Foo::Bar.extend(Foo::Bar) Klass.new.hello # "hello" Foo::Bar.hello # "hello" Klass.hello # undefined method `hello' for Klass:Class (NoMethodError)










