#总算是有时间把之前在RubyMonk上搞的那些菜鸟题目做了一遍,也顺便温习巩固下基础知识。
一、数组篇
1在下面的代码中,尝试提取超过五个字符的字符串。
names = ['rock', 'paper', 'scissors', 'lizard', 'spock']
names.each do |a|
puts a if(a.length>5)
end
2对于开发者而言,ruby之所以能这么流行的一个原因是它有着非常直观的API。很多时候,你都能在你脑海中猜到能完成你想要的目标的一些方法名称。尝试猜测一个你需要使用的方法来删除下面所给数组为“5”的元素。(注意是猜测哦,好吧,其实我早就知道了)
[1,3,5,4,6,7].delete_if{|m| m==5}
3从下面给出的数组中删除所有给出的偶数
[1,2,3,4,5,6,7,8,9].delete_if{|m| m%2==0}
原文:(Doing this in languages like C or Java would take you a lot of boiler plate code. The beauty of Ruby is in its concise but readable code.)
4给定一个包含有几个字符串的数组,编写一个length_finder方法,该方法接收一个数组为参数并够返回一个新数组,该新数组为对应数组参数的每个字符串元素的长度。(别吐槽我的水平了,我知道这个翻译的那是怎么听怎么别扭,应该能明白大概意思吧)Example:
Given ['Ruby','Rails','C42'] the method should return [4,5,3]
def length_finder(input_array)
input_array.map do |e|
e.length
end
end
4给定一个包含有多个单词的句子,编写一个名为“find_frequency”的方法,该方法有两个参数“sentence”和“word”,这两个参数都是字符串对象。并返回某一单词在该句子中的出现频率。示例:传入 'Ruby is The best language in the World' 和 'the',则返回“ 2”
提示: Array#count (用法自个儿查去)
def find_frequency(sentence, word)
sentence.downcase.split(" ").count(word.downcase)
end
二、字符串篇
1创建一个名为'random_select'的方法,该方法有两个参数,一个是数组对象array,另一个是数字n。该方法将返回从给定数组中随机选取n个新的元素组成新的数组。例如:给定数组[1,2,3,4,5]和2应该返回随机从这个数组中随机挑选的两个数字所组成的新数组。
PS: 两次调用该方法最好返回不同的结果。
def random_select(array, n)
result = []
n.times do
result << array[rand(array.length)]
end
result
end
2创建一个名为'sort_string'的方法,该方法接收一个字符串对象,并对这个字符串中的单词按照长度的升序进行重排序。假设没有其他的标点符号而只有单个空格分隔该字符串。例如:给定"Sort words in a sentence", 将返回"a in Sort words sentence".
def sort_string(string)
string.split(" ").sort{|a,b| a.length<=>b.length}.join(' ')
end
三、迭代器篇
1复制存储在数组变量source中值小于4的元素到数组变量destination
def array_copy(destination)
source = [1, 2, 3, 4, 5]
source.each do |a|
destination.push(a) if a< 4
end
destination
end
四、正则篇
1将下面给出字符串中的大写字母都改为数字“0”
'RubyMonk Is Pretty Brilliant'.gsub(/[A-Z]/,'0')
五、构建一个计算器
创建一个计算器类,能够在同一时间完成两个数字的加减法。(不太懂,原文:Create a class Calculator, which performs the addition and subtraction of two numbers at a time. The sample code explains the expected API.)
class Calculator
def add(num_1, num_2)
num_1 + num_2
end
def subtract(num_1, num_2)
num_1 - num_2
end
end
由于Rubygems官方网站被Wall了,导致Ruby程序员在线安装软件gem包的时候无法顺利进行,往往需要借助VPN才能成功安装,所以带来了很大的不便。
最近淘宝网提供了Rubygems的国内镜像站:http://ruby.taobao.org/
从淘宝的国内镜像网站在线下载和安装Gem包速度变得飞快! 强烈推荐大家使用此镜像站点:
例如要安装Rails,可以这样来做:
- gem sources -a http://ruby.taobao.org/
- gem install rails
如果是在Rails当中使用bundle,则需要修改Gemfile文件,将默认的
- source 'http://rubygems.org'
改成
- source 'http://ruby.taobao.org/'
此外淘宝也提供了Ruby官方网站镜像,可以方便快捷的下载各个Ruby版本。
-------------------------------------------------------------------------------------------------------------------------------------
Rubygems 镜像 - 淘宝网
如何使用?
$ gem sources -a http://ruby.taobao.org/ $ gem install foo
Rails 项目的用法
修改你的 Gemfile 将 http://rubygems.org 改为 http://ruby.taobao.org/
source 'http://ruby.taobao.org/' gem 'rails', '3.1.1' ...
Ruby 源代码下载
Ruby on Rails以其高度的易用性和灵活性著称,不过这些优点的背后还存在着性能的隐患。最近,资深Ruby on Rails作家David Berube提供了几个Ruby on Rails性能优化的技巧,对相关开发人员具有一定的借鉴意义。
Ruby on Rails以其高度的易用性和灵活性著称,不过这些优点的背后还存在着性能的隐患。最近,资深Ruby on Rails作家David Berube提供了几个Ruby on Rails性能优化的技巧,对相关开发人员具有一定的借鉴意义。
David Berube在文章中首先分析了Rails应用运行缓慢的原因:
- Rails总是会做一些假设为您加速开发。通常,这种假设是正确而有帮助的。不过,它们并不总能有益于性能,并且还会导致资源使用的效率低下——尤其是数据库资源。
- 另一个显著的挑战是N+1问题......这会导致很多小查询的执行,而不是一个单一的大查询。例如,ActiveRecord无从知道一组父记录中的哪一个会请求一个子记录,所以它会为每个父记录生成一个子记录查询。由于每查询的负荷,这种行为将导致明显的性能问题。
- 由于ActiveRecord 能够让如此众多的任务变得轻而易举,Rails开发人员常常会形成 “SQL 不怎样” 的一种态度,即便在更适合使用SQL的时候,也会避免SQL。创建和处理数量巨大的ActiveRecord对象的速度会非常缓慢,所以在有些情况下,直接编写一个无需实例化任何对象的SQL查询会更快些。
对于如何检测性能问题, David Berube提供了一些建议:
- 最好的工具之一是Rails开发日志,它通常位于每个开发机器上的log/development.log文件内。它具有各种综合指标:响应请求所花费的总时间、花费在数据库内的时间所占的百分比、生成视图所花时间的百分比等。
- 在生产期间,通过查看mysql_slow_log可以找到很多有价值的信息。
- 其中一个最强大也是最为有用的工具是query_reviewer插件。这个插件可显示在页面上有多少查询在执行以及页面生成需要多长时间。并且它还会自动分析 ActiveRecord生成的SQL代码以便发现潜在问题。例如,它能找到不使用MySQL 索引的查询,所以如果您忘记了索引一个重要的列并由此造成了性能问题,那么您将能很容易地找到这个列。此插件在一个弹出的
(只在开发模式下可见)中显示了所有这类信息。
针对N+1查询问题,David Berube举了一个未优化的代码示例:
<%@posts = Post.all(@posts).each do |p|%>
<%=p.category.name%>
<%=p.body%>
<%end%>
David Berube指出,上述代码生成了一个查询外加@posts内的每行一个查询。由于每查询的负荷,这可能会成为一个很大的挑战。罪魁祸首是对p.category.name的调用。这个调用只应用于该特定的post对象,而不是整个@posts数组。这种情况通过使用立即加载可以修复。立即加载(Eager loading)意味着Rails将自动执行所需的查询来加载任何特定子对象的对象。Rails将使用一个JOIN SQL语句或一个执行多个查询的策略。不过,假设指定了将要使用的所有子对象,那么将永远不会导致N+1的情形,在N+1情形下,一个循环的每个迭代都会生成额外的一个查询。优化后的代码如下:
<%@posts = Post.find(:all, :include=>[:category] @posts.each do |p|%>
<%=p.category.name%>
<%=p.body%>
<%end%>
比较复杂的情况包括嵌套的立即加载和间接的立即加载。
除了解决N+1问题之外,David Berube还提供了一些优化建议:
- 使用Rails提供的分组和聚合(grouping and aggregate)函数
- 用Rails定制 SQL
- 确保获得cache-money缓存插件
不过目前动态语言在企业开发中的应用还不够广泛,很多企业只是用它来做一些粘合系统的工作,并没有承担起主力开发语言的重任。尤其是在底层系统开发方面,动态语言远没有在Web开发方面那么风光。在运行时效率和虚拟机稳定性方面的不足,使得动态语言注定无法与编译型语言竞争,并取代它们在高性能领域的地位。然而,动态语言也有自己的优势所在。如何克服自己的劣势,将优势发扬光大,便是每一位动态语言开发者所面临的机遇和挑战。
我所在的团队用了近两年的时间,将一个电信领域的公司绝大部分的生产系统用动态语言(主要是Python)重写。包括短/彩信消息网关、业务订阅服务、座席查询系统、销售支撑系统,乃至搜索引擎等多个核心系统,都在重写之列。重写的理由很多,一方面原有系统无论是从性能上,还是从应对需求变化的能力上,都已经不能满足业务发展的需要;另外一方面,动态语言的诸多优势,也是我们重写的动力。这里仅以开发这些系统时获得的经验,来谈谈动态语言在应用时的优缺点。
maybe很多ror新人如我会跟着那个rails guide小试牛刀搭一个自己的blog。一步步下来小有体会到rails的强劲,也没出啥问题,到的comment那一块,X,对了半天源代码甚至复制粘贴到Sublime Text,奈何还是坑爹的冒出错误:
undefined method `error_messages' for #<ActionView::Helpers::FormBuilder:0x3bff910>
嗯,好吧,简体和繁体的guide都是基于rails 3.0的。于是去官方看了下rails 3.1的那个guide。很明显的,源代码少了
“<%= f.error_messages %>”
这一行。删去后妥妥的....
查了下error_messages这玩意的用处,没查到,有木有高端指教一下啊~~
好吧,顺便借机叹息一下,中文的ror资料更新的好慢啊,想看中文版的AWDWR第四版却迟迟不出。难不成真的要去看英文版的??最近在看Ruby on Rails Tutorial,还有github上的英文已经各种够吃力了!!~~~~(>_<)~~~~
之前发现一个外国的ruby学习网站http://www.rubymonk.com 但是鉴于自己的英文水平不咋滴,一直都没怎么关注。最近硬着头皮读了下,其实读英文的技术文章好像没想象中那么难,很多词汇都大概能理解,实在不懂的一个复制粘贴也就大概懂了。之所以不想去翻阅英文书籍大概就是因为看到一大堆要绞尽脑才能读懂的文字产生了恐惧感吧!以后要开始进修英文的ruby资料才行,中文版的资料更新实在是太慢了,完全跟不上脚步。
可能鉴于部分童鞋跟我一样不怎么稀饭读英文的东东,水平也跟我一样那么菜。所以小锅来个大牺牲+殉难为大家搞下翻译,把rubymonk上的英文题目翻译过来。感觉很适合新人,高端的大牛们请无视吧。嗯,准备搞个专题系列吧。有啥不对的望多给些建议和意见。题目答案将在另外一个帖子给出,或者可以自己到rubymonk的网站上去查询(好吧,我不会告诉你这个网站加载有些慢的),大牛们可以给出自己更犀利的解题方法。(大牛曰:这些那么菜的问题还要多犀利?难道要加个异常处理)
一、数组篇
1在下面的代码中,尝试提取超过五个字符的字符串。
names = ['rock', 'paper', 'scissors', 'lizard', 'spock']
2对于开发者而言,ruby之所以能这么流行的一个原因是它有着非常直观的API。很多时候,你都能在你脑海中猜到能完成你想要的目标的一些方法名称。尝试猜测一个你需要使用的方法来删除下面所给数组为“5”的元素。(注意是猜测哦,好吧,其实我早就知道了)
[1,3,5,4,6,7]
3从下面给出的数组中删除所有给出的偶数
[1,2,3,4,5,6,7,8,9]
原文:(Doing this in languages like C or Java would take you a lot of boiler plate code. The beauty of Ruby is in its concise but readable code.) 4给定一个包含有几个字符串的数组,编写一个length_finder方法,该方法接收一个数组为参数并够返回一个新数组,该新数组为对应数组参数的每个字符串元素的长度。(别吐槽我的水平了,我知道这个翻译的那是怎么听怎么别扭,应该能明白大概意思吧)
def length_finder(input_array)
#your code
end
4给定一个包含有多个单词的句子,编写一个名为“find_frequency”的方法,该方法有两个参数“sentence”和“word”,这两个参数都是字符串对象。并返回某一单词在该句子中的出现频率。示例:传入 'Ruby is The best language in the World' 和 'the',则返回“ 2”
提示: Array#count (用法自个儿查去)
def find_frequency(sentence, word)
# Your code here
end
二、字符串篇
1创建一个名为'random_select'的方法,该方法有两个参数,一个是数组对象array,另一个是数字n。该方法将返回从给定数组中随机选取n个新的元素组成新的数组。例如:给定数组[1,2,3,4,5]和2应该返回随机从这个数组中随机挑选的两个数字所组成的新数组。
PS: 两次调用该方法最好返回不同的结果。
def random_select(array, n)
# your code here
end
2创建一个名为 'sort_string'的方法,该方法接收一个字符串对象,并对这个字符串中的单词按照长度的升序进行重排序。假设没有其他的标点符号而只有单个空格分隔该字符串。例如:给定"Sort words in a sentence", 将返回"a in Sort words sentence".
def sort_string(string)
# your code here
end
三、迭代器篇
1复制存储在数组变量source中值小于4的元素到数组变量destination
def array_copy(destination) source = [1, 2, 3, 4, 5]
# your code destination end
2迭代是在Ruby _blocks_用法最常被引用的的例子之一 。 Array#each方法接收数组中的每一个元素然后依次传递到代码块中。你会发现for循环在ruby中几乎不被使用。Array#each和 its siblings are the de-facto standard。(~~(╯﹏╰)b)
现在,再做一遍上面我们用for循环完成的题目,但是,这次要用新的方法咯!
def array_copy(destination)
source = [1, 2, 3, 4, 5]
# your code
destination
end
四、正则篇
1将下面给出字符串中的大写字母都改为数字“0”
'RubyMonk Is Pretty Brilliant'
五、构建一个计算器
创建一个计算器类,能够在同一时间完成两个数字的加减法。(不太懂,原文:Create a class Calculator, which performs the addition and subtraction of two numbers at a time. The sample code explains the expected API.)
class Calculator
def add(a, b)
# your code here
end
def subtract(a, b)
# your code here
end
end
六、类与面向对象
(最近各种忙,都木有时间更新这个了)
proc是代码块的对象形式,它的行为就像一个代码块。Lambda的的行为略有不同,它的行为更像方法而非代码块。调用一个proc则像对代码块进行yield,而调用一个lambda则像调用一个方法。在Ruby1.9中的,可以通过Proc对象的实例方法 lambda? 来判定该实例是一个proc还是lambda,如果返回值为真,那么它是一个lambda,否则为一个proc。
代码块、proc和lambda中的return语句
在一个代码块中的return语句不仅仅会从调用代码块的迭代器返回,它还会从调用迭代器的方法返回。例如:
def test
puts "entering method"
1.times{puts "entering block";return}
puts "exiting method"
end
test
proc与代码块类似,因此如果调用的proc执行一个return语句,它会试图从代码块(这个代码块被转换为一个proc)所在的方法中返回。比如:
def test
puts “entering method”
p =Proc.new {puts “entering proc”;return}
p.call
puts “exiting method”
end
test
不过,因为proc经常在不同方法间传递,在proc中使用return语句会十分诡异。在proc被调用时,在句法上包含该proc的方法已经返回:
def procBuilder(message)
Proc.new {puts message ;return}
end
def test
puts “entering method”
p = procBuilder(“entering proc”)
p.call
puts “exiting method”
end
test
在把代码块转换成对象后,可以四处传递该对象,并且在“上下文”之外使用。如果这样做,则要承担从一个已经返回的方法中返回的风险。就像本例所示那样。当这种情况发生时,Ruby会抛出一个LocalJumpError异常。
当然,在这个臆造的例子中,可以通过去掉多余的return语句来修复这个问题。不过return语句并非总是多余的,这时可以通过使用lambda而非proc来修复这个问题。如前所述,lambda更像方法而非代码块。这样,在lambda中的return语句仅仅从lambda自身返回。而不会从产生lambda的方法中返回:
def test
puts “entering method”
p = lambda{puts “entering lambda”;return}
p.call
puts “exiting method”
end
test
Lambda中的return仅仅从lambda自身返回,这个事实意味着我们根本无须考虑LocalJumpError;
def lambdaBuilder(message)
lambda {puts message;return}
end
def test
puts ”exiting method”
l =lambdaBuilder(“entering lambda”)
l.call
puts “exiting method”
end
test
代码块、proc和lambda中的break语句
当我们用Proc.new创建一个proc对象时,这个Proc.new就是break语句应该返回的地方,当我们调用proc对象的时候,这个迭代器已经返回了,因此,用Proc.new创建一个顶级break语句是说不通的:
def test
puts “entering test method ”
proc =Proc.new{puts “entering proc”;break}
proc.call
puts “exiting test method”
end
test
如果通过迭代器方法的&参数方式创建一个proc,我们可以调用它让该迭代器方法返回;
def iterator (&proc)
puts “entering iterator”
proc.call
puts “exiting test method”
end
def test
iterator {puts “entering proc”;break)
end
test
Lambda类似于方法,因此,如果把一个break语句单独地放在那里,而不是出现在循环或者迭代方法中是说不通的。下面的语句,没有任何东西可以被break,你可能认为它会失败。
不过,在这种情况下,break的行为与return一样;
def test
puts “entering test method”
lambda=lambda{puts “entering lambda”;break;puts “exiting lambda”}
lambda.call
puts “exiting test method”
end
test
今天学习到的一种比较新的,挺有趣的特性,说新只是以前学JAVA和PHP的时候木有接触过。貌似Ruby的这一特性是从Perl那里继承而来,所以学习过Perl的程序员应该比较熟悉。
flip-flop
以下内容摘自《Ruby编程语言》
当..和...操作符被用在一个条件式,或者一个循环中时,它们不会创建Range对象。相反地,它们将创建一种特殊的布尔表达式,名为flip-flop.和比较以及相等表达式一样,一个flip-flop表达式的值也为true或者false。但是一个flip-flop表达式的特殊之处在于,它的值依赖于此前的求值结果,这就意味着flip-flop表达式具有与其关联的状态,所以你可能会认为一个flip-flop是一个某种类型的对象,但事实上flip-flop并不是对象,而是Ruby表达式。Ruby解释器在处理完一个flip-flop表达式之后,将为它在内部存储一个解析后的表现形式,其中就保存了该表达式的状态(只是作为一个布尔值)。
有了这些背景知识后,请看下面代码中的flip-flop。第一个..创建一个Range对象,第二个..则创建了一个flip-flop表达式:
(1..10).each {|x| print x if x==3..x==5 }
在一个由条件式或者循环所构成的上下文中,一个flip-flop由两个通过..操作符相连的布尔表达式构成。除非其左侧表达式为true,否则一个flip-flop表达式就位false,而且在左侧表达式为true之前,它的值都会是false。一旦该表达式为true那么它就会“flips”到一个持久的true状态。它会保持该状态,而且对其后续的求值也返回true,直到其右侧的表达式为true为止。如果右侧表达式为 true了那么该flip-flop就会“flops”回一个持久的false状态,对其后续的求值也返回false,直到其左侧表达式再次成为true为止。
在上面的代码例子中,该flip-flop被反复求值,相应的x的值也从1增加到10.起初,它的状态为false,而且在x等1和2的时候一直是false。当x等于3的时候,该flip-flop的状态就成为true。在x等于4和5的时候,该flip-flop的状态又回到了false,而且对于后续的x,它总是返回false。上述代码的执行结果是打印出345 。
可以使用..或...来编写flip-flop。起差别在于:当一个..flip-flop为true时,它会返回true,同时测试它的右侧表达式以决定是否需要将其内部状态设置回false;而对于...flip-flop来说,它等到下一次求值的时候才测试其右侧表达式。观察下面的代码:
# Prints "3" . Flips and flops back when x==3
(1..10).each {|x| print x if x==3..x>=3}
# Print "34" . Flis when x==3 and flops when x==4
(1..10).each {|x| print x if x==3...x>=3}
注:flip-flop其中一个意思是突变,flip和flop都有翻转的意思
这篇东东之前也发在了一个新生的ruby社区www.rubyeye.com上,不过新社区人气还木有搞起来,就ctrl c & ctrl v到这儿来。稀饭ruby的可以到www.rubyeye.com逛逛。
