非常感谢!
非常感谢!
多谢分享!
确实不错,真学到知识了,如果广告都这样,社会就更和谐了,哈,顶下!
module D
puts self.class # 输出 Module
class << self
puts self.class # 输出 Class
def say_hello_of_d
puts 'D say hello'
end
end
end
Module 的 singleton_class 就是 Class,不能 include 或 extend 到一个 class 中。 我能想到的就是用 delegate, 不过太难看了,不确定是否有问题。
require 'delegate'
module D
class << self
def say_hello_of_d
puts 'D say hello'
end
end
end
class Y < DelegateClass(D.singleton_class)
def initialize
super(D)
end
end
y = Y.new
y.say_hello_of_d
谢谢楼主的感悟和分享,加油!
好东西,谢谢分享!
多谢!!
@chiangdi a, = 3, 5 如同 a, _ = 3, 5 告诉 ruby,赋值号左边有类似给多个变量赋值的行为,即不把 [3,5] 赋给 a, 只把 3 赋值给 a
这些在 <>书中有讲。
在 c/c++ 里 a = 3, b = 5 是可以的,中间的逗号,就是逗号运算符,
在 ruby 中 a = 3, b = 5 ruby 并没有逗号运算符,这个表达式就相当于 a = 3, (b = 5), 也就是 a = 3, 5 ruby 的赋值操作有这样的特性,左边一个变量,右边多个值时,ruby 会创建一个包含右边值的数组,并赋值给左边的变量。
可以试试 a, = 3, b = 5 p a, b
当然不建议这么做。
多谢!
用 TracePoint 可以监听:return, :raise 事件,当发生异常时,会监听到:raise 事件,接着是:return 事件,利用这一特性,可以基本实现获取每一层栈帧的局部变量,代码如下:
class LocalVariablesTracer
class << self
attr_accessor :raised_exception
def start
@raised_exception = nil
_define_dump_func
TracePoint.trace(:return, :raise) do |tp|
case tp.event
when :raise
@raised_exception = tp.raised_exception
when :return
if @raised_exception
@raised_exception.instance_eval {
@func_bindings ||= {}
@func_bindings[tp.method_id] = tp.binding
}
end
end
end
end
private
def _define_dump_func
Exception.class_eval do
def dump_local_variables(out = $stderr)
if @func_bindings
backtrace.grep(/\`(\w+)\'/) do
func = $1.to_sym
b = @func_bindings[func]
local_variables = b.eval("local_variables").map { |var|
%/#{var}: #{b.eval("#{var}")}/
}
out.puts "#{func}: #{local_variables}"
LocalVariablesTracer.raised_exception = nil
end
end
end
end
end
end
end
使用例子:
LocalVariablesTracer.start
def func
a = 1
b = 1
raise "hello"
end
def func1
name = "xzgyb"
msgs = ["hello", "world"]
func
end
begin
func1
rescue Exception => ex
ex.dump_local_variables
end
-@ 是一元负号操作符,用于在类中定义一元负号操作符的实现, 可以看看 puts 1.-@ puts -1.-@
多谢,收藏!
感谢分享,学习
if 'bar'.in?(params[:foo]) ... end rescue nil
感谢!
对 ruby 爱好者来说,这太好了,感谢!
linux 系的平台下,shell 会进行通配符的展开,和 ruby 没关系。
windows 下,cmd 并不会进行通配符的展开,ruby 为了保持和 linux 的行为一致,做了 glob 处理, 参见源码 (ruby.c):
void
ruby_sysinit(int *argc, char ***argv)
{
#if defined(_WIN32)
void rb_w32_sysinit(int *argc, char ***argv);
rb_w32_sysinit(argc, argv);
#endif
...
}
其中的 rb_w32_sysinit(argc, argv) 会调用 rb_w32_cmdvector(GetCommandLine(), argv);进行参数的 glob 处理。
且 ruby 没有提供什么选项,也无法提供,因为 linux 的 shell 缘故。
确实没招了,只能转义。
a1.class.send(:define_method, :m) { puts self }
这个中间表,是 rails 内部用于实现多对多关联使用的 join table, 也不需要用页面来管理吧,用不着搞个 scaffold.
当提示存在时,是否覆盖,按提示来吧,选 n 不覆盖,让 rails 只创建新的文件, 完事后,在 controller 和 controller_test 中在补上相应的代码。
或者直接手工创建相应的文件,也不是什么麻烦事。
我觉得 rails generate 只是给了我们一个起点,就像一些 ide 的向导一样, 剩下的是我们自己的选择,但不能完全依赖它。
@skandhas : 呵呵,!!! ~_~ !!!
ruby1.9 之前是可以的,ruby1.9 之后,好像是因为安全问题吧,具体不太清楚, 另 require_relative 也是可用的。
@imsoz, 不客气。
CALL、FCALL、VCALL 这几个,是属于 ruby 内部实现机制,
ruby1.9.3 p0 compile.c:4050
case NODE_CALL:
case NODE_FCALL:
case NODE_VCALL:{ /* VCALL: variable or call */
/*
call: obj.method(...)
fcall: func(...)
vcall: func
*/
这个纯属个人爱好,因为看到过,所以这里说上几句,不好意思,希望不会误导到你。
因为对于 private 为什么会是这样的设计,我也疑惑过,所以这里在多说一下, 权当做参考。
在全局作用域(也就是一般说的 toplevel)中定义的方法,在某个类中可以直接调用, 类似其他的语言中的全局函数的效果,原因就是初始脚本运行时,ruby vm 默认打开了 Object 类,并且设置方法的默认可见性为 private, 则在 toplevel 中定义的方法都是 Object 的方法且是 private 的, 由于 ruby 中的一切都是从 Object 继承的, 故 ruby 对于 private 方法的这一设计,使得在任何类的方法中, 都可以用这种类似全局函数调用的形式来进行调用。
另外附带说一句, kernel 中的 load 函数 load( file_name, wrap=false )
如果 wrap 设为 true, 就是使得 ruby vm 默认不是用 Object,而是创建一个匿名的 module, 目的是不让它污染 toplevel 的名字空间。
另外同意@skandhas 的说法,人生苦短,ruby 的宗旨就是让程序员快乐的编程。
在 ruby 中方法调用形式分为
对于 FCALL 和 VCALL,ruby 并不校验该方法是否 private,这也正是实现了那种调用全局函数的效果,比如:
def global_func
puts 'global_func'
end
class A
def method
global_func # 如果使用self.global_func, 则提示global_func为private
end
end
a = A.new
a.method
不客气
str.split(//u).size, 应该是 ruby1.8 的时候,String 内部就是 ascii 编码, ruby1.9,String 可以原生支持多种编码了, 只要你的源文件使用 utf-8 编码, size 和 length,算出来的长度就是正确的字符个数 bytesize 是字节数
来个不一样的,仿照 Agile Web Development with Rails
class Product
attr_accessor :name, :unit_price, :pack_count, :pack_price
def initialize(name, unit_price, pack_count, pack_price)
@name, @unit_price, @pack_count, @pack_price =
name, unit_price, pack_count, pack_price
end
def ==(other)
@name == other.name
end
def self.products_data
@@products_data ||= {}
end
def self.add(name, unit_price, pack_count = nil, pack_price = nil)
self.products_data[name] = Product.new(name, unit_price, pack_count, pack_price)
end
def self.find_by_name(name)
self.products_data[name]
end
end
require './product'
class CartItem
attr_reader :product, :quantity
def initialize(product)
@product = product
@quantity = 1
end
def increment_quantity
@quantity += 1
end
def price
if @product.pack_price.nil?
@product.unit_price * @quantity
else
pack_items_count = @quantity / @product.pack_count
rest_quantity = @quantity - pack_items_count * @product.pack_count
@product.pack_price * pack_items_count +
@product.unit_price * rest_quantity
end
end
end
require './cart_item'
class Cart
attr_reader :items
def initialize
@items = []
end
def add_product(product)
current_item = @items.find { |item| item.product == product }
if current_item
current_item.increment_quantity
else
@items << CartItem.new(product)
end
end
def total_cost
@items.inject(0) { |sum, item| sum += item.price}
end
end
require './product'
require './cart'
class Terminal
def initialize
@cart = Cart.new
end
def set_price(params)
Product.add(params[:name],
params[:unit_price],
params[:pack_count],
params[:pack_price])
end
def scan(p_code)
product = Product.find_by_name(p_code)
raise "Product #{p_code} not found!" if product.nil?
@cart.add_product(product)
end
def total_cost
@cart.total_cost
end
end
if $0 == __FILE__
terminal = Terminal.new
terminal.set_price(name:'A', unit_price: 2, pack_count: 4, pack_price: 7)
terminal.set_price(name:'B', unit_price: 12)
terminal.set_price(name:'C', unit_price: 1.25, pack_count: 6, pack_price: 6)
terminal.set_price(name:'D', unit_price: 0.15)
terminal.scan('A')
terminal.scan('A')
terminal.scan('A')
terminal.scan('A')
terminal.scan('B')
terminal.scan('C')
puts "Total cost #{terminal.total_cost}"
end