Ruby meta programming 4(eval/class_eval/module_eval/instance_eval)

之所以有不同的eval方法,只是因为在不同的上下文中;你也可以使用eval+bind参数完全替换class_eval/module_eval/instance_eval的

# "#{exp}" evaluates it  as a string and not as an expression, whereas eval( exp ) evaluates a string as an expression.
exp = "2+4"
puts( eval( exp )) 
puts( "#{exp}" ) 


# eval method can evaluate strings spanning many lines
eval( 'def aMethod( x ) 
   return( x * 2 ) 
end 

num = 100  
puts( "This is the result of the calculation:" ) 
puts( aMethod( num ))' ) 

# special types of eval
class MyClass 
 def initialize 
   @aVar = "Hello world" 
 end 
end 

ob = MyClass.new 
p( ob.instance_eval { @aVar } )   
p( ob.instance_eval( "@aVar" ) ) 

# eval can evaluate expressions of arbitrary complexity
# such ass create method to String class
String::class_eval{ define_method(:bye){ puts("goodbye" ) } } 
"Hello".bye    #=> “goodbye” 

Ruby meta programming 3(closure)

# closure
10.times{ |i| print("=")}
puts("closure")
x = "hello world"

ablock = Proc.new { puts( x ) }

def aMethod( aBlockArg )
    x = "goodbye"
    aBlockArg.call
end

puts( x )
ablock.call
#this will output "hello world", because when the ablock is create, the value of x is "hello world"
aMethod( ablock )
ablock.call
puts( x )

def calcTax( taxRate ) 
   return lambda{ 
      |subtotal| 
      subtotal * taxRate 
      }  
end 

# create two closure, the taxRate is 0.1, then the returned block accept one argument as subtotal
salesTax = calcTax( 0.10 ) 
vat = calcTax( 0.175 ) 

print( "Tax due on book = ") 
print( salesTax.call( 10 ) )     #<= prints: 1.0 

print( "\nVat due on DVD = ") 
print( vat.call( 10 ) ) 

# local variable will not effect the block argument x
x = 3000 

c3 = lambda{  
   |x| 
   return x + 100   
} 

someval=1000 
someval=c3.call(someval); 
puts("\n" + someval.to_s) 
someval=c3.call(someval); puts(someval)  
puts( x ) 

Ruby meta programming 2(define_method/attr_accessor)

下面是使用四种方式来完成同一个类的方法。
第一种是直接定义get和set方法;
第二种是通过define_method来动态的定义;
第三种是通过attr_accessor来动态的定义;
第四种也是通过attr_accessor来动态的定义,只是去除了冗余;

10.times{ |i| print("=")}
puts("Writing Code That Writes Code")
class CarModel
  def engine_info=(info)
    @engine_info = info
  end

  def engine_info
    @engine_info
  end

  def engine_price=(price)
    @engine_price = price
  end

  def engine_price
    @engine_price
  end

  def wheel_info=(info)
    @wheel_info = info
  end

  def wheel_info
    @wheel_info
  end

  def wheel_price=(price)
    @wheel_price = price
  end

  def wheel_price
    @wheel_price
  end

  def airbag_info=(info)
    @airbag_info = info
  end

  def airbag_info
    @airbag_info
  end

  def airbag_price=(price)
    @airbag_price = price
  end

  def airbag_price
    @airbag_price
  end

  def alarm_info=(info)
    @alarm_info = info
  end

  def alarm_info
    @alarm_info
  end

  def alarm_price=(price)
    @alarm_price = price
  end

  def alarm_price
    @alarm_price
  end

  def stereo_info=(info)
    @stereo_info = info
  end

  def stereo_info
    @stereo_info
  end

  def stereo_price=(price)
    @stereo_price = price
  end

  def stereo_price
    @stereo_price
  end
end

class CarModel2
  FEATURES = ["engine", "wheel", "airbag", "alarm", "stereo"]

  FEATURES.each do |feature|
    define_method("#{feature}_info=") do |info|
      instance_variable_set("@#{feature}_info", info)
    end

    define_method("#{feature}_info") do
      instance_variable_get("@#{feature}_info")
    end

    define_method "feature_price=" do |price|
      instance_variable_set("@#{feature}_price", price)
    end

    define_method("#{feature}_price") do
      instance_variable_get("@#{feature}_price")
    end
  end
end

class CarModel3
  attr_accessor :engine_info, :engine_price, :wheel_info, :wheel_price, :airbag_info, :airbag_price, :alarm_info, :alarm_price, :stereo_info, :stereo_price
end

class CarModel4
  # define a class macro for setting features
  def self.features(*args)
    args.each do |feature|
      attr_accessor "#{feature}_price", "#{feature}_info"
    end
  end

  # set _info and _price methods for each of these features
  features :engine, :wheel, :airbag, :alarm, :stereo
end

car = CarModel4.new
car.engine_info = "111"
puts car.engine_info
#list all methods 
car.methods.sort.each do |method|
  puts "method #{method} belong to " + car.method(:"#{method}").inspect
end

http://rubylearning.com/blog/2010/11/23/dont-know-metaprogramming-in-ruby/

Ruby的Block

一般来说,用花括号括起来的代码段,称之为block

Some codes segmetn in “The Book for Ruby” can’t run successful in Ruby 2.3
like below code:
a = “hello world”.split(//).each{ |x| newstr << x.capitalize }
will throw undefined variable, so I change the code in below code and let it
run

# block example
p [1, 2, 3, 4, 5].collect { |number| number + 1 }
p [1, 2, 3, 4, 5].select { |number| number.odd? }
p [1, 2, 3, 4, 5].detect { |number| number.even? }
b3 = [1,2,3].collect{|x| x*2}  
p b3
b4 = ["hello","good day","how do you do"].collect{|x| x.capitalize } 
p b4
b5 = ["hello","good day","how do you do"].each{|x| x.capitalize }  
p b5
b6 = ["hello","good day","how do you do"].each{|x| x.capitalize! } 
p b6

# output: ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
a1 = "hello world".split(//)
p a1

=begin
output:
H
HE
HEL
HELL
HELLO
HELLO
HELLO W
HELLO WO
HELLO WOR
HELLO WORL
HELLO WORLD
=end
newstr = ""
a1.collect{ |x| newstr<< x.capitalize; puts newstr; } 

#define diff  proc using diff format
a = Proc.new{|x| x = x*10; puts(x) } 
b = lambda{|x| x = x*10; puts(x) } 
c = proc{|x| x.capitalize! }       

a.call(10);
b.call(10);
p c.call("test");

#pass argument to block
def caps( anarg )  
  yield( anarg ) 
end 

caps( "a lowercase string" ){ |x| x.capitalize! ; puts( x ) } 

#named proc and yield
a = lambda{ puts "one" }
b = lambda{ puts "two" }
c = proc{ puts "three" } 
def abc3( a, b, c, &d) 
  a.call 
  b.call 
  c.call 
  #below two code is same
  d.call    #<= block &d 
  yield    #<= also block &d 
end 
abc3(a, b, c){puts "four"}

#pass x, y, z to block
def xyz 
   x = 1 
   y = 2 
   z = 3 
   yield( x, y, z )
end 
xyz{ |a,b,c| puts(a+b+c) } 

# the yield will pass 100 to block instead of "hello world"
a = "hello world" 

def foo 
   yield 100 
end 

puts( a ) 
foo{ |a| puts( a ) } # 100

puts( a )      # Hello world

Ruby中的 class method, instance method, singleton method/class

singleton method/class 从效果来说,两者没有什么区别

# class method
10.times{ |i| print("=")}
puts("class/instance method")
class MyClass   
   def MyClass.classMethod 
      puts( "This is a class method" ) 
   end 

   def self.classMethod3 
      puts( "This is a class method3" ) 
   end 

   def instaceMethod
      puts("instance method")
   end
end

def MyClass.classMethod2
  puts( "This is a class method2" ) 
end 

MyClass.classMethod
MyClass.classMethod2
MyClass.classMethod3
#MyClass.instaceMethod # undefined method

# singleton method
10.times{ |i| print("=")}
puts("singleton method")
aaa = MyClass.new
def aaa.test
  puts "singleton method"
end

class << aaa 
   def test2 
      puts( "singleton class method" ) 
   end 
end

aaa.test
aaa.test2
aaa.instaceMethod
# aaa.classMethod # undefined method
aaa.class.classMethod

Ruby中的Symbol

A symbol is an identifier whose first character is a colon ( : ), so :this
is a symbol and so is :that .
symbol是以:开头的。
A symbol is not: it is not a string, it is not a constant and it is not a
variable. A symbol is, quite simply, an identifier with no intrinsic meaning
other than its own name.
symbol不是字符串,不是常量,不是变量,它只是一个符号,来表示它自己的名字

同一个symbol在不同的上下文中是一样的.

顺便提一句,值相同的Fixnum的哦bject_id也是一样的

 #from Ruby doc
module One
  class Fred
  end
  $f1 = :Fred
end
module Two
  Fred = 1
  $f2 = :Fred
end
def Fred()
end
$f3 = :Fred
$f1.object_id   #=> 2514190
$f2.object_id   #=> 2514190
$f3.object_id   #=> 2514190

Ruby 中的各种变量(local/instance/class/global variable and assignment method)

从注释中可以看出每段代码中使用的变量类型

# local variable
10.times{ |i| print("=")}
puts("local variable")
1.times do
  a = 1
  b = "a"
  puts "local variables in the block: #{local_variables.join ", "}"
end

puts "no local variables outside the block" if local_variables.empty?

# instance variable
10.times{ |i| print("=")}
puts("instance variable")
class C
  def initialize(value)
    @instance_variable = value
  end

  def value
    @instance_variable
  end
end

object1 = C.new "some value"
object2 = C.new "other value"

p object1.value # prints "some value"
p object2.value # prints "other value"

#class variable
10.times{ |i| print("=")}
puts("class variable")
class A
  @@class_variable = 0

  def value
    @@class_variable
  end

  def update
    @@class_variable = @@class_variable + 1
  end
end

class B < A
  def update
    @@class_variable = @@class_variable + 2
  end
end

a = A.new
b = B.new

puts "A value: #{a.value}" #0
puts "B value: #{b.value}" #0

puts "update A"
a.update

puts "A value: #{a.value}"
puts "B value: #{b.value}"

puts "update B"
b.update

puts "A value: #{a.value}"
puts "B value: #{b.value}"

puts "update A"
a.update

puts "A value: #{a.value}"
puts "B value: #{b.value}"

#global variable
10.times{ |i| print("=")}
puts("global variable")
$global = 0

class E
  puts "in a class: #{$global}"

  def my_method
    puts "in a method: #{$global}"

    $global = $global + 1
    $other_global = 3
  end
end

E.new.my_method

puts "at top-level, $global: #{$global}, $other_global: #{$other_global}"

# Assignment method
10.times{ |i| print("=")}
puts("Assignment method")
class F
  @value
  attr_accessor :value

  def my_method
    #self.value = 42
    @value = 42; 
    puts "local_variables: #{local_variables.join ", "}"
    puts "@value: #{@value.inspect}"
  end
end

F.new.my_method

PHP post combine

if you post as below, PHP will parse below post as array[0] == Country,
Country has three property

Country%5Bcode%5D=1&Country%5Bname%5D=2&Country%5Bpopulation%5D=1
Country[code]:1
Country[name]:2
Country[population]:1

fop's font

what’s fop:
http://xmlgraphics.apache.org/fop/
1. using TTF reader to generate metric xml file and let fop using it

cd to fop's main directory,
java -cp "build/*;lib/*" org.apache.fop.fonts.apps.TTFReader -ttcname "MS Gothic" c:\Windows\Fonts\msgothic.ttc msgothic.xml

java -cp "build/*;lib/*" org.apache.fop.fonts.apps.TTFReader c:\Windows\Fonts\msgothic.ttc test.xml  --> list all font in ttc collection file

add below line to fop’s config file’s fonts section:

<font embed-url="file:///c:Windows/Fonts/msgothic.ttc" sub-font="MS Gothic">
    <font-triplet name="MSGothic" style="normal" weight="normal"/>
</font>

start fop with -c configfile.xml argument
2. add to fop’s config file’s font section
start fop with -c configfile.xml argument.

but you fo file need specify font for chinese character, fop will displya ##
for your chinise character if not set font;
if you set the wrong font, it will display a warning message to console to
tell you some character not found with instead with default #.
For example MS Gothic font not has 贾,so it will display as #
if you enable auto-detect, fop will create a font cache file(fop-fonts.cache)
for speed up next time