ubuntu 下利用ndiswrapper安装无线网卡驱动

首先 安装 ndiswrapper
ubuntu下也就是 ndisgtk   (用于安装无线网卡驱动)

sudo apt-get install ndisgtk

安装好了之后,找到你的无线网卡在windows下的驱动文件(含有.inf的目录)(可以从网上下载也可以从驱动盘中获得),将该目录中的文件拷到主目录的新建文件夹中,
执行 sudo ndiswrapper -i yourname.inf     //yourname是你驱动inf的文件名称
安装以后会在  /etc/ndiswrapper/  下面建立一个相应的目录youname,

到该目录下(cd /etc/ndiswrapper)执行  sudo ndiswrapper -l   //查看驱动安装ok了没 显示driver installed

写入配置文件:
sudo ndiswrapper -m           (让ndiswrapper在启动时自动加载,
无线网卡会在系统启动初始化hotplug subsysytem时装载(这时卡上的电源灯才会亮) )

modprobe ndiswrapper        (让linux加载ndiswrapper module)

这样就可以配置无线网卡了,在SSID中输入无线路由名,在“无线安全性”中选择“WPA及WPA2个人”,然后输入密码即可。

配置好后重启下无线网络即连接成功。

终端中的步骤:

sudo apt-get install ndisgtk

# sudo ndiswrapper -i net8192u.inf

cd /etc/ndiswrapper/

sudo ndiswrapper -l

sudo ndiswrapper -m

sudo ndiswrapper -mi   \保证重启之后不再设置

sudo modprobe ndiswrapper

最后设置无线网络连接。

Posted in Uncategorized

No one is coming

Happiness: resilience, optimism, self-faith, sence-meaning, social behavior, helping others
Stop blaming others. Take responsibility of your life.
No one is coming. You are responsible for your life, for your self-confidence, for your self-esteem, for your happiness.
No one is coming. It’s up to you to make the most out of this experience.
People are comfortably numb.
Clutivating personal growth, working on the positive.
Idealism and good intentions are not enough to resolve conflict.

Posted in Uncategorized

rails中的业务处理Active Record Transactions

Transactions are protective blocks where SQL statements are only permanent if they can all succeed as one atomic action. The classic example is a transfer between two accounts where you can only have a deposit if the withdrawal succeeded and vice versa.

Transactions是保护行的代码块,用于只有你能够完成所有的元操作才permanent SQL statements(执行sql语句)。经典的例子是一个在两个帐号之间的业务,这里你只能在转账成功后才能有一个deposit存款,反之也是。

Transactions enforce the integrity of the database and guard the data against program errors or database break-downs. So basically you should use transaction blocks whenever you have a number of statements that must be executed together or not at all.

Transactions 保障了数据库的有效性,能够防止程序错误或者数据库故障对数据的影响。因此基本上你应该使用Transactions代码块无论何时你需要一系列的声明必须在一起执行或者什么都不做。

For example:

ActiveRecord::Base.transaction do
  david.withdrawal(100)
  mary.deposit(100)
end

This example will only take money from David and give it to Mary if neither withdrawal nor deposit raise an exception. Exceptions will force a ROLLBACK that returns the database to the state before the transaction began. Be aware, though, that the objects will not have their instance data returned to their pre-transactional state.

这个例子仅仅从David那里转账一些钱给Mary如果汇款或者存款都没有异常抛出。意外情况发生则会强制一个回滚数据库到业务开始的状态。请保持清醒,这样,对象将不会有实例数据回到到它们的每一个业务来源地。

Different Active Record classes in a single transaction

Though the transaction class method is called on some Active Record class, the objects within the transaction block need not all be instances of that class. This is because transactions are per-database connection, not per-model.

即使transaction类方法被一些的Active Record class调用,在transaction代码块中的对象并不需要所有的实例都是来自那个类。这是因为transaction是基于每个数据连接的而不是每个model。

In this example a balance record is transactionally saved even though transaction is called on the Account class:

在这个例子中余额记录被transactionally保存即使transaction也被Account类调用。

Account.transaction do
  balance.save!
  account.save!
end

The transaction method is also available as a model instance method. For example, you can also do this:

transaction在model实例方法中也是可用的。例如你可以这样做:

balance.transaction do
  balance.save!
  account.save!
end

Transactions are not distributed across database connections

A transaction acts on a single database connection. If you have multiple class-specific databases, the transaction will not protect interaction among them. One workaround is to begin a transaction on each class whose models you alter:

一个transaction动作是一个单个的数据库连接。如果你的数据库指定了多个类,transaction将不会保护他们全部的相互影响。一个解决办法是开始一个transaction包含你要改变的model的每一个类:

Student.transaction do
  Course.transaction do
    course.enroll(student)
    student.units += course.units
  end
end

This is a poor solution, but fully distributed transactions are beyond the scope of Active Record.

这是一个无赖的办法,但是完整的区域业务超出了Active Record的范围。

save and destroy are automatically wrapped in a transaction

Both save and destroy come wrapped in a transaction that ensures that whatever you do in validations or callbacks will happen under its protected cover. So you can use validations to check for values that the transaction depends on or you can raise exceptions in the callbacks to rollback, including after_* callbacks.

保存和删除都是包装在一个业务中的确保无论你何时做验证或者回调都会在它的保护下。因此你可以使用验证来检查业务中的值在此基础上或者你可以在回调中抛出异常来回滚,包含after_* callbacks。

As a consequence changes to the database are not seen outside your connection until the operation is complete. For example, if you try to update the index of a search engine in after_save the indexer won’t see the updated record. The after_commit callback is the only one that is triggered once the update is committed. See below.

这样有一个后果就是在你的操作完成之前,数据库的改变都不会表现出来(不会突出于你的连接之外)。例如,如果你尝试使用after_save更新一个搜索引擎的索引,索引者将不会发现更新的记录。after_commit回调是仅有的一个它会在一旦更新完成就被触发。看下面。

Exception handling and rolling back

Exception handling and rolling back

Also have in mind that exceptions thrown within a transaction block will be propagated (after triggering the ROLLBACK), so you should be ready to catch those in your application code.

同样也要留心在一个业务代码块中的异常抛出将会被传播(在触发回调之后)。因此你应该准备好在应用程序中抓取这些异常。

One exception is the ActiveRecord::Rollback exception, which will trigger a ROLLBACK when raised, but not be re-raised by the transaction block.

Warning: one should not catch ActiveRecord::StatementInvalid exceptions inside a transaction block. ActiveRecord::StatementInvalid exceptions indicate that an error occurred at the database level, for example when a unique constraint is violated. On some database systems, such as PostgreSQL, database errors inside a transaction cause the entire transaction to become unusable until it’s restarted from the beginning. Here is an example which demonstrates the problem:

# Suppose that we have a Number model with a unique column called 'i'.
Number.transaction do
  Number.create(:i => 0)
  begin
    # This will raise a unique constraint error...
    Number.create(:i => 0)
  rescue ActiveRecord::StatementInvalid
    # ...which we ignore.
  end

  # On PostgreSQL, the transaction is now unusable. The following
  # statement will cause a PostgreSQL error, even though the unique
  # constraint is no longer violated:
  Number.create(:i => 1)
  # => "PGError: ERROR:  current transaction is aborted, commands
  #     ignored until end of transaction block"
end

One should restart the entire transaction if an ActiveRecord::StatementInvalid occurred.

应该重新开始业务如果ActiveRecord::StatementInvalid发生了。

Nested transactions

transaction calls can be nested. By default, this makes all database statements in the nested transaction block become part of the parent transaction. For example, the following behavior may be surprising:

transaction可以嵌套调用。默认情况下,这将会将被嵌套的transaction作为其中所有的数据库声明的父业务。

User.transaction do
  User.create(:username => 'Kotori')
  User.transaction do
    User.create(:username => 'Nemu')
    raise ActiveRecord::Rollback
  end
end

creates both “Kotori” and “Nemu”. Reason is the ActiveRecord::Rollback exception in the nested block does not issue a ROLLBACK. Since these exceptions are captured in transaction blocks, the parent block does not see it and the real transaction is committed.

In order to get a ROLLBACK for the nested transaction you may ask for a real sub-transaction by passing :requires_new => true. If anything goes wrong, the database rolls back to the beginning of the sub-transaction without rolling back the parent transaction. 如果有任何错误,数据库将会回滚到子业务的开始状态,并没有回滚父业务。If we add it to the previous example:

User.transaction do
  User.create(:username => 'Kotori')
  User.transaction(:requires_new => true) do
    User.create(:username => 'Nemu')
    raise ActiveRecord::Rollback
  end
end

only “Kotori” is created. (This works on MySQL and PostgreSQL, but not on SQLite3.)

Most databases don’t support true nested transactions. At the time of writing, the only database that we’re aware of that supports true nested transactions, is MS-SQL. Because of this, Active Record emulates nested transactions by using savepoints on MySQL and PostgreSQL. See dev.mysql.com/doc/refman/5.0/en/savepoint.html for more information about savepoints.

Callbacks

There are two types of callbacks associated with committing and rolling back transactions: after_commit and after_rollback.

after_commit callbacks are called on every record saved or destroyed within a transaction immediately after the transaction is committed. after_rollback callbacks are called on every record saved or destroyed within a transaction immediately after the transaction or savepoint is rolled back.

These callbacks are useful for interacting with other systems since you will be guaranteed that the callback is only executed when the database is in a permanent state. For example, after_commit is a good spot to put in a hook to clearing a cache since clearing it from within a transaction could trigger the cache to be regenerated before the database is updated.

Caveats

If you’re on MySQL, then do not use DDL operations in nested transactions blocks that are emulated with savepoints. That is, do not execute statements like ‘CREATE TABLE’ inside such blocks. This is because MySQL automatically releases all savepoints upon executing a DDL operation. When transaction is finished and tries to release the savepoint it created earlier, a database error will occur because the savepoint has already been automatically released. The following example demonstrates the problem:

Model.connection.transaction do                           # BEGIN
  Model.connection.transaction(:requires_new => true) do  # CREATE SAVEPOINT active_record_1
    Model.connection.create_table(...)                    # active_record_1 now automatically released
  end                                                     # RELEASE savepoint active_record_1
                                                          # ^^^^ BOOM! database error!
end

Note that “TRUNCATE” is also a MySQL DDL statement!

Posted in Uncategorized

ruby变量

变量,实例变量,类变量,甚至还有”常量”其实都只是对象引用。它们引用对象,但是它们并不是对象本身。因此,它们可以被动态地改变,甚至引用另一种不同类型的对象。

  因为这一灵活性,所以必须在Ruby中进行一些约定以帮助每个人都知道某个变量正为代码所使用。其实,你已经看到了其中之一(@符号,它意味着这是一个实例变量)。其它的变量,方法和类命名约定列于下表1中。

  · 局部变量和方法参数以一个小写字母开头。
  · 方法名字以一个小写字母开头。
  · 全局变量以一个$开头。
  · 实例变量以一个@开头。
  · 类变量以两个@开头。
  · 常数以一个大写字母开头(它们经常被指定全部大写)。
  · 类和模块名以一个大写字母开头。

局部变量 全局变量 实例变量 类变量 常数 类名 方法名
aVar $Var @var @@var VAR MyClass myMethod
name $debug @lastName @@interest PI Rectangle area

        表1.这个表包含了在Ruby编码约定下的相关示例

Posted in Uncategorized

OO设计原则总结

 设计原则是基本的工具,应用这些规则可以使你的代码更加灵活,更容易维护,更容易扩展。
基本设计原则
封装变化(Encapsulate what varies
面向接口编程而非实现(code to an interface rather than to an implementation)
优先使用组合而非继承(favor Composition over inheritance)
SRP(Single responsibility Principle
    单一职责。系统中的每一个对象都应该只有1个单独的职责,而所有对象所关注的就是自身职责的完成。
    每一个职责都是一个设计的变因,需求变化的时候,需求变化反映为类的职责的变化。当你系统里的对象都只有一个变化的原因时,你就已经很好的遵循了SRP原则了。如果一个类承担了过多的职责,就等于把这些职责耦合在一起了。一个职责的变化就可能消弱或者抑制这个类其它的职责的能力。这种设计会导致脆弱的设计。当发生变化时,设计会遭到意想不到的破坏。
    SRP让这个系统更容易管理和维护,因为不是所有的问题都耦合在一起。
    内聚(Cohesion)其实是SRP原则的另外一个名字。你写了高内聚的软件其实就是很好的应用了SRP原则。 
DRY(Don’t repeat yourself Principle)
    不要重复自己的工作。通过抽取公共部分放置在一个地方来避免重复的代码或功能实现。
    DRY确保women代码容易维护和复用。确保每一个需求和功能在你的系统中只实现一次,否则就存在浪费!系统的用例不存在交集,所以我们的代码更不应该重复。从这个角度看DRY就不只是在说代码了。DRY关注的是系统内的信息和行为都放在一个单一的,明显的位置。
    DRY原则:如何对系统职能进行良好的分割!职责清晰的界限一定程度上保证了代码的单一性。
    
OCP(Open-Close Principle)
    开闭原则OCP关注的是灵活性,改动是通过增加代码进行的,而不是改动现有的代码。
    OCP的应用限定在可能会发生的变化上,通过创建抽象来隔离以后发生的同类变化。
    OCP传递这样一个思想:一旦你写出来可以工作的代码,就要努力保证这段代码可以一直工作。这就成了你的编码的一个底线。一旦我们的代码质量到了一个水平,我们就要尽最大努力保证代码质量不回退。这样就要求我们面对一个问题的时候不会使用凑活的方法来解决,或者说放任自流的方式来解决一个问题(比如:代码添加了无数对特定数据的处理,特化的代码越来越多,代码意图开始含糊不清,这就开始质量退化了。)
    OCP背后的机制:封装和抽象。封闭是建立在抽象的基础上的,使用抽象获得显示的封闭。继承是OCP最简单的例子。除了子类化和方法重载我们还有一些更优雅的方法来实现比如组合。
    那么如何在不改变源代码(关闭修改)的情况下更改它的行为呢?答案就是抽象。
    正确的做法就是开发人员仅对频繁变化的部分做出抽象。拒绝不成熟的抽象,这和抽象本身一样的重要
    OCP是OOD很多说法的核心,如果这个原则有效的应用,我们可以获得更强的可维护性 可重用性 灵活性 健壮性。。然而LSP是OCP成为可能的主要原则之一。
LSP(Liskov substitution Principle)
子类必须能够替换基类。LSP关注的是怎样良好的使用继承。必须清楚是使用一个Method还是要扩展它,但是绝对不是改变它。
        LSP让我们得出一个重要的结论:一个模型如果孤立的看,并不具有真正意义的有效性,模型的有效性只能通过它的客户程序来表现。必须根据设计的使用者做出的合理假设来审视它。而假设是难以预测的,知道设计臭味出现的时候才处理他们。
DIP(Dependency-Inversion Principle)
依赖反转/依赖倒置高层模块不依赖底层模块 两者都应只依赖于抽象。
    抽象不依赖于细节, 而细节依赖于抽象。
    高层模块:包含了应用程序中重要的策略选择和业务模型。这些高层模块使其所在的应用程序区别于其他。
框架设计的核心原则: 如果高层模块依赖底层模块,那么在不同的上下文中重用高层模块会变得十分困难。然而,如果高层模块不依赖于底层模块,那么高层模块就可以非常容易的被重用。
    这里的倒置不仅仅指依赖关系的倒置同时也是接口所有权的倒置。
   Hollywood原则: Don’t call us。 we will call you. 底层模块实现了在高层模块声明并被高层模块调用的接口。
   DIP的简单的启发规则:依赖于抽象。程序汇总所有的依赖都应依赖于抽象类或接口。
   如果一个类很稳定,那么依赖于它不会造成伤害。然而我们自己的具体类大多是不稳定的,通过把他们隐藏在抽象接口后面可以隔离不稳定性。
   
   依赖倒置可以应用于任何一个类向另一个类发送消息的地方。。。(还不是很理解)
   依赖倒置原则是实现许多面向对象技术多宣称的好处的基本底层机制,是面向对象的标志所在。   

ISP(Interface Segregation Principle)
接口隔离原则
使用多个专门的接口比使用一个单一的接口总要好:从一个客户类的角度来讲,一个类对另外一个类的依赖性应当是建立在最小的接口上。
如果接口不是高内聚的,一个接口可以分成N组方法,那么这个接口就需要使用ISP来处理一下了~~。
        一个接口中包含了太多的行为时候,导致他们的客户程序之间产生不正常的依赖关系,我们要做的就是分离接口,实现解耦。使用了ISP后客户程序看到的是多个内聚的接口。

 

Posted in Uncategorized

[進階]使用 Facade Pattern 取代 Model Callbacks by xdite

What is “callbacks”?

Rails 的 ActiveRecord 提供了相當方便的 callbacks,能讓開發者在寫 Controller 時,能夠寫出更加 DRY 的程式碼:

  • before_crearte
  • before_save
  • after_create
  • after_save

在從前,在 Controller 裡面想要再 object 儲存之後 do_something,直觀的思路會是這樣:

class PostController
  def create
    @post = Post.new(params[:post])
    @post.save
    @post.do_something
    redirect_to posts_path
  end
end 

當時的最佳模式:通常是建議開發者改用 callbacks 或者是 Observer 模式實作。避免 controller 的髒亂。

  • callbacks : after_create

或者是使用 Observer

class PostController < ApplicationController
  def create
    @post = Post.new(params[:post])
    @post.save
    redirect_to posts_path
  end
end
class PostObserver < ActiveRecord::Observer
  def after_create(post)
    post.do_something
  end
end
class Post < ActiveRecord::Base
  protected
  def do_something
  end
end

使用 callbacks 所產生的問題

callbacks 雖然很方便,但也產生一些其他的問題。若這個 do_something 是很輕量的 db update,那這個問題還好。但如果是很 heavy 的 hit_3rd_party_api 呢?

在幾個情形下,開發者會遇到不小的麻煩。

  • Model 測試:每次在測試時都會被這個 3rd_party_api 整到,因為外部通訊很慢。
  • do_something_api 是很 heavy 的操作:每次寫測試還是會被很慢的 db query 整到。
  • do_something_api 是很輕微的 update:但是綁定 after_save 操作,在要掃描資料庫,做大規模的某欄位修改時,會不小心觸發到不希望引發的 callbacks,造成不必要的效能問題。

當然,開發者還是可以用其他招數去閃開:

比如說若綁定 after_save 。

可以在 do_somehting 內加入對 dirty object 的偵測,避免被觸發:

 def do_somthing
  # 資料存在,且變動的欄位包括 content
  if presisited? && changed.include?(“content”)
    the_real_thing
  end
 end

 但這一招並不算理想,原因有幾:

  1. 每次儲存還是需要被掃描一次,可能有效能問題。
  2. 寫測試時還是會呼叫到可能不需要引發的 do_somehting。
  3. if xxx && yyy 這個 condiction chain 可能會無限延伸下去。

 Facade Pattern

那麼要怎樣才能解決這個問題呢?其實我們應該用 Facade Pattern 解決這個問題。

設計模式裡面有一招 Facade Pattern,這一招其實是沒有被寫進 Design Pattern in Ruby 中的。Russ Olson 有寫了一篇文章解釋沒有收錄的原因:因為在 Ruby 中,這一招太簡單太直觀,所以不想收錄 XDDD。但他還是在網站上提供當時寫的草稿,供人參考。

What is Facade Pattern?

Facade Pattern 的目的是「將複雜的介面簡化,將複雜與瑣碎的步驟封裝起來,對外開放簡單的介面,讓客戶端能夠藉由呼叫簡單的介面而完成原本複雜的程式演算。」(來源

延伸閱讀: (原創) 我的Design Pattern之旅[5]:Facade Pattern (OO) (Design Pattern) (C/C++)

實際舉例:

在上述的例子中,其實 do_something 有可能只會在 PostController 用到,而非所有的 model 操作都「需要」用到。所以我們 不應該將 do_somehting 丟進 callbacks(等於全域觸發),再一一寫 case 去閃避執行

與其寫在 callbacks 裡。我們更應該寫的是一個 Service Class 將這一系列複雜昂貴的行為包裝起來,以簡單的介面執行。
class PostController < ApplicationController
  def create
  CreatePostService(params[:post])
  redirect_to posts_path
  end
 end
class CreatePostService
  def self.create(params)
    post = Post.new(params[:post])
    post.save
    post.do_something_a
    post.do_something_b
    post.do_something_c
  end
end  而在寫測試,只需要對 PostCreateService 這個商業邏輯 class 寫測試即可。而 PostController 和 Post Model 就不會被殃及到。

小結

不少開發者討厭測試的原因,不只是「因為」寫測試很麻煩的原因,「跑一輪測試超級久」也是讓大家很不爽的主因之一。

其實不是這些測試框架寫的爛造成「寫測試很麻煩」、「執行測試超級久」。而是另有其他因素。

許多資深開發者逐漸意識到,真正的主因是在於目前 Rails 的 model 的設計,耦合度太高了。只要沾到 db 就慢,偏偏 db 是世界的中心。只是測某些邏輯,搞到不小心觸發其他不需要測的東西。

ActiveRecord 的問題在於,讓開發者太誤以為 ORM = model。其實開發者真正要寫的測試應該是對商業邏輯的測試,不是對 db 進行測試。

所以才會出現了用 Facade Pattern 取代 callbacks 的手法。

其他

MVC 其實有其不足的部份。坦白說,Rails 也不是真正的 MVC,而是 Model2

目前 MVC 其實是不足的,演化下來,開發者會發現 User class 裡面會開始出現這些東西:

  • current_user.buy_book(book)
  • current_user.add_creadit_point(point)

這屬於 User 裡面應該放的 method 嗎?well,你也可以說適合,也可以說不適合。

適合的原因是:其實你也不知道應該放哪裡,這好像是 User 執行的事,跟他有關,那就放這裡好了!不然也不知道要擺哪裡。

不適合的原因是:這是一個「商業購買行為」。不是所有人都會購物啊。這應該是一個商業購買邏輯。但是….也不知道要放在哪啊。

一直到最近,James Copelin 提出了:DCI 去補充了現有的 MVC 的不足,才算勉強解決了目前浮現的這些問題。

DCI ,與本篇談到的 Facade Pattern 算是頗類似的手法。

有關於 DCI ( Data, Context, Interaction ) 的文章,我會在之後發表。我同時也推薦各位去看這方面的主題。這個方向應該會是 Rails 專案設計上未來演化的方向之一。

 

Posted in Uncategorized

python ruby geek by django社区and ruby-china

by ruby-china 由 gaicitadie瞎扯淡 节点

统计一个字符串在另一个字符串中出现的次数,python只需要一个count方法:

>>> '11ab1111ab111ac11111'.count('ab') 2

huacnlee 1楼, 于24小时前回复 irb> ’11ab1111ab111ac11111′.scan(“ab”).count
2
ywencn 2楼, 于24小时前回复 1.9.2p290 :001 >  ’11ab1111ab111ac11111′.count(‘ab’)
 => 5
楼主想表达什么?

ywencn 3楼, 于24小时前回复 哎呀。。。怎么python和ruby的count还不一样,哈哈

huacnlee 4楼, 于24小时前回复 Ruby 的 “”.count 统计的是后面所有的字符

dreamrise 5楼, 于24小时前回复 貌似_who还写过一个python与ruby转换的程序?

gaicitadie 6楼, 于23小时前回复 奥运奖牌榜:
国家 金牌数 银牌数 铜牌数
china 37 26 11
usa 30 22 50
russia 30 33 20

中国习惯上先按金牌数排名,金牌数一样的按银牌数再排,如果银牌数再一样就按铜牌数排:

>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:(-x[1],-x[2],-x[3]))
[('china', 37, 26, 11), ('russia', 30, 33, 20), ('usa', 30, 22, 50)]
美国习惯上金牌银牌铜牌都是奖牌,所以按奖牌总数排序:

>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:-(x[1]+x[2]+x[3]))
[('usa', 30, 22, 50), ('russia', 30, 33, 20), ('china', 37, 26, 11)]
python的排序达到了类似SQL查询的能力,只需要告诉它排序的条件就可以了,python为数据而生

gaicitadie 7楼, 于23小时前回复 上面的例子是python模拟SQL的order by功能,下面的例子用python模拟SQL的where条件查询

统计金牌数超过35的国家:

>>> [x for x in [('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)] if x[1]>35]
[('china', 37, 26, 11)]
统计奖牌总数超过100的国家:

>>> [x for x in [('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)] if x[1]+x[2]+x[3]>100]
[('usa', 30, 22, 50)]
huyong36 8楼, 于23小时前回复 @gaicitadie ruby是

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1] > 35}
[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1] + x[2] + x[3] > 100}
quakewang 9楼, 于23小时前回复 #6楼 @gaicitadie
order by 的ruby代码

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|m| [-m[1], -m[2], -m[3]]}
[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|m| -(m[1] + m[2] + m[3])]}
skandhas 10楼, 于23小时前回复 从楼主的例子直接翻译到Ruby
1 中国习惯上先按金牌数排名,金牌数一样的按银牌数再排,如果银牌数再一样就按铜牌数排:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|x| [-x[1],-x[2],-x[3]]}
2 美国习惯上金牌银牌铜牌都是奖牌,所以按奖牌总数排序:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|x| -(x[1]+x[2]+x[3])}
3 统计金牌数超过35的国家:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1] >35}
4 统计奖牌总数超过100的国家:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1]+x[2]+x[3] > 100}
这两个语言都挺类似,我觉得ruby的select更直观。

另 楼主这个帖子想表达什么?没看出什么来。如果说只通过sorted就说明python是为数据而生的话,那ruby不也是吗。哈哈

daqing 11楼, 于23小时前回复 我来写个Ruby版本的。

第一个,奖牌排序:

data = [[:china, 27, 26, 11], [:usa, 20, 22, 50], [:russia, 30, 33, 20]]

data.sort_by { |x| [-x[1], -x[2], -x[3]] } # 中国排序方法,按金/银/铜牌数
data.sort_by { |x| -(x[1] + x[2] + x[3]) } # 美国排序方法,按奖牌总数
第二个,奖牌统计:

data.select { |x| x[1] > 35 } # 金牌数超过35的国家
data.select { |x| x[1] + x[2] + x[3] > 100 } # 奖牌总数超过100的国家
哪个更简洁,一目了然了吧。

daqing 12楼, 于23小时前回复 原来大家都在回复。。等我写出来才发现。

daqing 13楼, 于23小时前回复 #10楼 @skandhas 看了你的方法,才想到,select是更直接的做法。collect方法会包含nil值。

reus 14楼, 于23小时前回复 Why I Hate Advocacy
http://www.perl.com/pub/2000/12/advocacy.html

gaicitadie 15楼, 于23小时前回复 总统选举投票,初步唱票记录:

['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
根据唱票记录统计每人的票数并按从多到少排序

>>> l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
>>> sorted(set([(i, l.count(i)) for i in l]), key=lambda x:-x[1])
[('Jim', 4), ('bush', 2), ('obama', 1)]
clearJiang 16楼, 于23小时前回复 #15楼 @gaicitadie 不如直接用collections.Counter

gaicitadie 17楼, 于23小时前回复 #16楼 @clearJiang 低版本没有collections

daqing 18楼, 于23小时前回复 总统选举投票

l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
l.uniq.collect { |x| [x, l.count(x)] }
=> [["Jim", 4], ["bush", 2], ["obama", 1]]
skandhas 19楼, 于22小时前回复 #15楼 @gaicitadie
根据唱票记录统计每人的票数并按从多到少排序:

l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
l.group_by{|i| i}.map{|k,v| [k,v.length] }
quakewang 20楼, 于22小时前回复 python要和ruby比 文件、字符操作或者数组、Hash操作的便利性绝对完败,要砸场还不如在性能上一棍子打死ruby。

bony 21楼, 于22小时前回复 这样的帖子应该多一点。长知识。@skandhas cool.

quakewang 22楼, 于22小时前回复 #15楼 @gaicitadie

['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama'].inject(Hash.new(0)) {|h, e| h[e] += 1; h}.sort_by{|e| -e[1]}
daqing 23楼, 于22小时前回复 说实话,Python的lambda匿名函数,跟Ruby的Block相比,从书写上就败了。

gaicitadie 24楼, 于22小时前回复 随机设置验证码的4个字符(不包括图片处理部分)

>>> import random
>>> s = ‘ABCDEFGHIJKLMNPRSTUVWXYZ’
>>> ”.join(random.sample((s),4))
‘EXSG’
>>> ”.join(random.sample((s),4))
‘TGYN’
>>> ”.join(random.sample((s),4))
‘MEYP’
>>> ”.join(random.sample((s),4))
‘TGIF’
>>> ”.join(random.sample((s),4))
‘JDWF’
quakewang 25楼, 于22小时前回复 #24楼 @gaicitadie

(‘A’..’Z’).to_a.sample(4).join
reus 26楼, 于22小时前回复 #15楼 @gaicitadie 你这个算法是O(n ^ 2)的,应该用reduce

def stat(acc, x):
  acc.setdefault(x, 0)
  acc[x] += 1
  return acc
sorted(reduce(stat,
  ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama'], {}).iteritems(),
    key = lambda x: -x[1])
huyong36 27楼, 于22小时前回复 @skandhas cool,加上个排序。

gaicitadie 28楼, 于22小时前回复 #26楼 @reus reduce不如列表解析快,虽然list.count会重复统计

skandhas 29楼, 于22小时前回复 #27楼 @huyong36
对,是忘了排序

l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
l.group_by{|i| i}.map{|k,v| [k,v.length] }.sort_by{|name,count| -count }
huacnlee 30楼, 于22小时前回复 风格不同而已,用起来都是一样方便。这个就是让我喜欢 Python 和 Ruby 的原因之一。

reus 31楼, 于22小时前回复 #28楼 @gaicitadie
就是慢在count调用上,for i in l遍历数组,且每个元素又再count遍历一次,O(n ^ 2)
reduce只需要遍历一次,O(n)
不信可以测试下

huyong36 32楼, 于22小时前回复 这帖应该是捧场帖,我喜欢这样的学习。

raecoo 33楼, 于22小时前回复 受用

hysios 34楼, 于21小时前回复 •字符串查找
# python
>>> ’11ab1111ab111ac11111′.count(‘ab’)
2
# Ruby
ruby-1.9.2-p290 >   ’11ab111123ab111ac11111′.count ‘ab’, ‘b’
2
hysios 35楼, 于21小时前回复 •奖牌排序
# python
>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:(-x[1],-x[2],-x[3]))
[('china', 37, 26, 11), ('russia', 30, 33, 20), ('usa', 30, 22, 50)]
# ruby
ruby-1.9.2-p290 > [['china',37,26,11], ['usa',30,22,50],['russia',30,33,20]].sort_by {|name,j,y,t| [-j,-y,-t] }
 => [["china", 37, 26, 11], ["russia", 30, 33, 20], ["usa", 30, 22, 50]]
hysios 36楼, 于21小时前回复 •奖牌统计
# python
>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:-(x[1]+x[2]+x[3]))
[('usa', 30, 22, 50), ('russia', 30, 33, 20), ('china', 37, 26, 11)]
# ruby
ruby-1.9.2-p290 > [['china',37,26,11], ['usa',30,22,50],['russia',30,33,20]].sort_by {|name,j,y,t| [-j + -y + -t] }
 => [["usa", 30, 22, 50], ["russia", 30, 33, 20], ["china", 37, 26, 11]]
kfll 37楼, 于21小时前回复 捧场..
js:

’11ab1111ab111ac11111′.match(/ab/g).length;
’11ab1111ab111ac11111′.split(‘ab’).length – 1;
中式排名:

[[37, 26, 11], [30, 22, 50], [30, 33, 20]].sort().reverse();
hysios 38楼, 于21小时前回复 总统选举投票,初步唱票记录:

# ruby
>>> l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
>>> sorted(set([(i, l.count(i)) for i in l]), key=lambda x:-x[1])
[('Jim', 4), ('bush', 2), ('obama', 1)]
# ruby
ruby-1.9.2-p290 >  ['bush','Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama'].each_with_object({}) {|name,s| s[name] = s.fetch(name,0) + 1 }.sort
 => [["Jim", 4], ["bush", 3], ["obama", 1]]
huyong36 39楼, 于21小时前回复 #34楼 @hysios

’11ab111123ab111ac11111′.count ‘ab’, ‘b’
这样不对吧…这样只是找出来字符串里出现b的次数。

irb(main):106:0> ’11ab111123ab111ac11111b’.count ‘ab’, ‘b’
=> 3
hysios 40楼, 于21小时前回复 @huyong36 thx count是没办法实现的, 别的方法也不错

huyong36 41楼, 于20小时前回复 #40楼 @hysios 恩,请教

irb(main):115:0> ’11ab111123ab111c11111′.count  ‘a’
=> 2
irb(main):114:0> ’11ab111123ab111c11111′.count  ‘ab’
=> 4
字符可以统计,为什么字符串不能。。

jhjguxin 42楼, 于20小时前回复 @huyong36
count([other_str]+) → fixnum click to toggle source
Each other_str parameter defines a set of characters to count. The intersection of these sets defines the characters to count in str. Any other_str that starts with a caret (^) is negated. The sequence c1–c2 means all characters between c1 and c2.

Guest 43楼, 于20小时前回复 gaicitadie = [['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].tap do |man|
  def man.make_self(&process); process.call self; end
  def man.become_egghead
    `python -c “print( sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:(-x[1],-x[2],-x[3])) )”`
  end
  def man.glow_up
    dont_be_shy = true
    unless self.respond_to? :more_elegant, dont_be_shy
      def self.more_elegant
        self.sort_by { |country, glods, silvers, bronzes| [-glods,-silvers,-bronzes] }
      end
    end
    if self.respond_to? :become_egghead
      class << self; remove_method :become_egghead; end
    end
    self
  end
end
gaicitadie.make_self &:become_egghead
gaicitadie.glow_up.make_self &:more_elegant
geekontheway 44楼, 于20小时前回复 #41楼 @huyong36 ruby的count 统计的是字符的数量 所以’11ab111123ab111c11111′.count ‘ab’等同于’11ab111123ab111c11111′.count ‘a’ + ’11ab111123ab111c11111′.count ‘b’

jhjguxin 45楼, 于20小时前回复 简而言之就是 取每一个字符的count的交集

huyong36 46楼, 于20小时前回复 @geekontheway @jhjguxin 3Q…

hysios 47楼, 于20小时前回复 #41楼 @huyong36 count 是统计所有的字符,并不会把参数当成字符串处理

FenRagwort 48楼, 于17小时前回复 合并两个字典/哈希,重复的项目,两个值相加

hash1.merge(hash2) {|dupkey,val1,val2| val1 + val2 }
楼主来个Python的写法?

hhuai 49楼, 于16小时前回复 method_missing, 楼主来个??

gaicitadie 50楼, 于14小时前回复 #48楼 @FenRagwort ,这个暂时只想到了普通方法

for k,v in hash2.items():
    if k in hash1:
        hash1[k] += v
    else:
        hash1.setdefault(k,v)
zw963 51楼, 于12小时前回复 #19楼 @skandhas

的确酷, 不说说实在的. group_by用来做这个, 真是有点大才小用了.

reus 52楼, 于12小时前回复 #49楼 @hhuai

class Foo:
  def __getattr__(self, name):
    def _foo(*arg, **kwargs):
      return self.method_missing(name, *arg, **kwargs)
    return _foo

  def method_missing(self, name, *args, **kwargs):
    print name, args, kwargs

a = Foo()
a.foo(‘bar’, baz = ‘baz’)

 

huacnlee 1楼, 于24小时前回复 irb> ’11ab1111ab111ac11111′.scan(“ab”).count
2
ywencn 2楼, 于24小时前回复 1.9.2p290 :001 >  ’11ab1111ab111ac11111′.count(‘ab’)
 => 5
楼主想表达什么?

ywencn 3楼, 于24小时前回复 哎呀。。。怎么python和ruby的count还不一样,哈哈

huacnlee 4楼, 于24小时前回复 Ruby 的 “”.count 统计的是后面所有的字符

dreamrise 5楼, 于24小时前回复 貌似_who还写过一个python与ruby转换的程序?

gaicitadie 6楼, 于23小时前回复 奥运奖牌榜:
国家 金牌数 银牌数 铜牌数
china 37 26 11
usa 30 22 50
russia 30 33 20

中国习惯上先按金牌数排名,金牌数一样的按银牌数再排,如果银牌数再一样就按铜牌数排:

>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:(-x[1],-x[2],-x[3]))
[('china', 37, 26, 11), ('russia', 30, 33, 20), ('usa', 30, 22, 50)]
美国习惯上金牌银牌铜牌都是奖牌,所以按奖牌总数排序:

>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:-(x[1]+x[2]+x[3]))
[('usa', 30, 22, 50), ('russia', 30, 33, 20), ('china', 37, 26, 11)]
python的排序达到了类似SQL查询的能力,只需要告诉它排序的条件就可以了,python为数据而生

gaicitadie 7楼, 于23小时前回复 上面的例子是python模拟SQL的order by功能,下面的例子用python模拟SQL的where条件查询

统计金牌数超过35的国家:

>>> [x for x in [('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)] if x[1]>35]
[('china', 37, 26, 11)]
统计奖牌总数超过100的国家:

>>> [x for x in [('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)] if x[1]+x[2]+x[3]>100]
[('usa', 30, 22, 50)]
huyong36 8楼, 于23小时前回复 @gaicitadie ruby是

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1] > 35}
[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1] + x[2] + x[3] > 100}
quakewang 9楼, 于23小时前回复 #6楼 @gaicitadie
order by 的ruby代码

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|m| [-m[1], -m[2], -m[3]]}
[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|m| -(m[1] + m[2] + m[3])]}
skandhas 10楼, 于23小时前回复 从楼主的例子直接翻译到Ruby
1 中国习惯上先按金牌数排名,金牌数一样的按银牌数再排,如果银牌数再一样就按铜牌数排:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|x| [-x[1],-x[2],-x[3]]}
2 美国习惯上金牌银牌铜牌都是奖牌,所以按奖牌总数排序:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|x| -(x[1]+x[2]+x[3])}
3 统计金牌数超过35的国家:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1] >35}
4 统计奖牌总数超过100的国家:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1]+x[2]+x[3] > 100}
这两个语言都挺类似,我觉得ruby的select更直观。

另 楼主这个帖子想表达什么?没看出什么来。如果说只通过sorted就说明python是为数据而生的话,那ruby不也是吗。哈哈

daqing 11楼, 于23小时前回复 我来写个Ruby版本的。

第一个,奖牌排序:

data = [[:china, 27, 26, 11], [:usa, 20, 22, 50], [:russia, 30, 33, 20]]

data.sort_by { |x| [-x[1], -x[2], -x[3]] } # 中国排序方法,按金/银/铜牌数
data.sort_by { |x| -(x[1] + x[2] + x[3]) } # 美国排序方法,按奖牌总数
第二个,奖牌统计:

data.select { |x| x[1] > 35 } # 金牌数超过35的国家
data.select { |x| x[1] + x[2] + x[3] > 100 } # 奖牌总数超过100的国家
哪个更简洁,一目了然了吧。

daqing 12楼, 于23小时前回复 原来大家都在回复。。等我写出来才发现。

daqing 13楼, 于23小时前回复 #10楼 @skandhas 看了你的方法,才想到,select是更直接的做法。collect方法会包含nil值。

reus 14楼, 于23小时前回复 Why I Hate Advocacy
http://www.perl.com/pub/2000/12/advocacy.html

gaicitadie 15楼, 于23小时前回复 总统选举投票,初步唱票记录:

['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
根据唱票记录统计每人的票数并按从多到少排序

>>> l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
>>> sorted(set([(i, l.count(i)) for i in l]), key=lambda x:-x[1])
[('Jim', 4), ('bush', 2), ('obama', 1)]
clearJiang 16楼, 于23小时前回复 #15楼 @gaicitadie 不如直接用collections.Counter

gaicitadie 17楼, 于23小时前回复 #16楼 @clearJiang 低版本没有collections

daqing 18楼, 于23小时前回复 总统选举投票

l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
l.uniq.collect { |x| [x, l.count(x)] }
=> [["Jim", 4], ["bush", 2], ["obama", 1]]
skandhas 19楼, 于22小时前回复 #15楼 @gaicitadie
根据唱票记录统计每人的票数并按从多到少排序:

l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
l.group_by{|i| i}.map{|k,v| [k,v.length] }
quakewang 20楼, 于22小时前回复 python要和ruby比 文件、字符操作或者数组、Hash操作的便利性绝对完败,要砸场还不如在性能上一棍子打死ruby。

bony 21楼, 于22小时前回复 这样的帖子应该多一点。长知识。@skandhas cool.

quakewang 22楼, 于22小时前回复 #15楼 @gaicitadie

['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama'].inject(Hash.new(0)) {|h, e| h[e] += 1; h}.sort_by{|e| -e[1]}
daqing 23楼, 于22小时前回复 说实话,Python的lambda匿名函数,跟Ruby的Block相比,从书写上就败了。

gaicitadie 24楼, 于22小时前回复 随机设置验证码的4个字符(不包括图片处理部分)

>>> import random
>>> s = ‘ABCDEFGHIJKLMNPRSTUVWXYZ’
>>> ”.join(random.sample((s),4))
‘EXSG’
>>> ”.join(random.sample((s),4))
‘TGYN’
>>> ”.join(random.sample((s),4))
‘MEYP’
>>> ”.join(random.sample((s),4))
‘TGIF’
>>> ”.join(random.sample((s),4))
‘JDWF’
quakewang 25楼, 于22小时前回复 #24楼 @gaicitadie

(‘A’..’Z’).to_a.sample(4).join
reus 26楼, 于22小时前回复 #15楼 @gaicitadie 你这个算法是O(n ^ 2)的,应该用reduce

def stat(acc, x):
  acc.setdefault(x, 0)
  acc[x] += 1
  return acc
sorted(reduce(stat,
  ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama'], {}).iteritems(),
    key = lambda x: -x[1])
huyong36 27楼, 于22小时前回复 @skandhas cool,加上个排序。

gaicitadie 28楼, 于22小时前回复 #26楼 @reus reduce不如列表解析快,虽然list.count会重复统计

skandhas 29楼, 于22小时前回复 #27楼 @huyong36
对,是忘了排序

l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
l.group_by{|i| i}.map{|k,v| [k,v.length] }.sort_by{|name,count| -count }
huacnlee 30楼, 于22小时前回复 风格不同而已,用起来都是一样方便。这个就是让我喜欢 Python 和 Ruby 的原因之一。

reus 31楼, 于22小时前回复 #28楼 @gaicitadie
就是慢在count调用上,for i in l遍历数组,且每个元素又再count遍历一次,O(n ^ 2)
reduce只需要遍历一次,O(n)
不信可以测试下

huyong36 32楼, 于22小时前回复 这帖应该是捧场帖,我喜欢这样的学习。

raecoo 33楼, 于22小时前回复 受用

hysios 34楼, 于21小时前回复 •字符串查找
# python
>>> ’11ab1111ab111ac11111′.count(‘ab’)
2
# Ruby
ruby-1.9.2-p290 >   ’11ab111123ab111ac11111′.count ‘ab’, ‘b’
2
hysios 35楼, 于21小时前回复 •奖牌排序
# python
>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:(-x[1],-x[2],-x[3]))
[('china', 37, 26, 11), ('russia', 30, 33, 20), ('usa', 30, 22, 50)]
# ruby
ruby-1.9.2-p290 > [['china',37,26,11], ['usa',30,22,50],['russia',30,33,20]].sort_by {|name,j,y,t| [-j,-y,-t] }
 => [["china", 37, 26, 11], ["russia", 30, 33, 20], ["usa", 30, 22, 50]]
hysios 36楼, 于21小时前回复 •奖牌统计
# python
>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:-(x[1]+x[2]+x[3]))
[('usa', 30, 22, 50), ('russia', 30, 33, 20), ('china', 37, 26, 11)]
# ruby
ruby-1.9.2-p290 > [['china',37,26,11], ['usa',30,22,50],['russia',30,33,20]].sort_by {|name,j,y,t| [-j + -y + -t] }
 => [["usa", 30, 22, 50], ["russia", 30, 33, 20], ["china", 37, 26, 11]]
kfll 37楼, 于21小时前回复 捧场..
js:

’11ab1111ab111ac11111′.match(/ab/g).length;
’11ab1111ab111ac11111′.split(‘ab’).length – 1;
中式排名:

[[37, 26, 11], [30, 22, 50], [30, 33, 20]].sort().reverse();
hysios 38楼, 于21小时前回复 总统选举投票,初步唱票记录:

# ruby
>>> l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
>>> sorted(set([(i, l.count(i)) for i in l]), key=lambda x:-x[1])
[('Jim', 4), ('bush', 2), ('obama', 1)]
# ruby
ruby-1.9.2-p290 >  ['bush','Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama'].each_with_object({}) {|name,s| s[name] = s.fetch(name,0) + 1 }.sort
 => [["Jim", 4], ["bush", 3], ["obama", 1]]
huyong36 39楼, 于21小时前回复 #34楼 @hysios

’11ab111123ab111ac11111′.count ‘ab’, ‘b’
这样不对吧…这样只是找出来字符串里出现b的次数。

irb(main):106:0> ’11ab111123ab111ac11111b’.count ‘ab’, ‘b’
=> 3
hysios 40楼, 于21小时前回复 @huyong36 thx count是没办法实现的, 别的方法也不错

huyong36 41楼, 于20小时前回复 #40楼 @hysios 恩,请教

irb(main):115:0> ’11ab111123ab111c11111′.count  ‘a’
=> 2
irb(main):114:0> ’11ab111123ab111c11111′.count  ‘ab’
=> 4
字符可以统计,为什么字符串不能。。

jhjguxin 42楼, 于20小时前回复 @huyong36
count([other_str]+) → fixnum click to toggle source
Each other_str parameter defines a set of characters to count. The intersection of these sets defines the characters to count in str. Any other_str that starts with a caret (^) is negated. The sequence c1–c2 means all characters between c1 and c2.

Guest 43楼, 于20小时前回复 gaicitadie = [['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].tap do |man|
  def man.make_self(&process); process.call self; end
  def man.become_egghead
    `python -c “print( sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:(-x[1],-x[2],-x[3])) )”`
  end
  def man.glow_up
    dont_be_shy = true
    unless self.respond_to? :more_elegant, dont_be_shy
      def self.more_elegant
        self.sort_by { |country, glods, silvers, bronzes| [-glods,-silvers,-bronzes] }
      end
    end
    if self.respond_to? :become_egghead
      class << self; remove_method :become_egghead; end
    end
    self
  end
end
gaicitadie.make_self &:become_egghead
gaicitadie.glow_up.make_self &:more_elegant
geekontheway 44楼, 于20小时前回复 #41楼 @huyong36 ruby的count 统计的是字符的数量 所以’11ab111123ab111c11111′.count ‘ab’等同于’11ab111123ab111c11111′.count ‘a’ + ’11ab111123ab111c11111′.count ‘b’

jhjguxin 45楼, 于20小时前回复 简而言之就是 取每一个字符的count的交集

huyong36 46楼, 于20小时前回复 @geekontheway @jhjguxin 3Q…

hysios 47楼, 于20小时前回复 #41楼 @huyong36 count 是统计所有的字符,并不会把参数当成字符串处理

FenRagwort 48楼, 于17小时前回复 合并两个字典/哈希,重复的项目,两个值相加

hash1.merge(hash2) {|dupkey,val1,val2| val1 + val2 }
楼主来个Python的写法?

hhuai 49楼, 于16小时前回复 method_missing, 楼主来个??

gaicitadie 50楼, 于14小时前回复 #48楼 @FenRagwort ,这个暂时只想到了普通方法

for k,v in hash2.items():
    if k in hash1:
        hash1[k] += v
    else:
        hash1.setdefault(k,v)
zw963 51楼, 于12小时前回复 #19楼 @skandhas

的确酷, 不说说实在的. group_by用来做这个, 真是有点大才小用了.

reus 52楼, 于12小时前回复 #49楼 @hhuai

class Foo:
  def __getattr__(self, name):
    def _foo(*arg, **kwargs):
      return self.method_missing(name, *arg, **kwargs)
    return _foo

  def method_missing(self, name, *args, **kwargs):
    print name, args, kwargs

a = Foo()
a.foo(‘bar’, baz = ‘baz’)

 

huacnlee 1楼, 于24小时前回复 irb> ’11ab1111ab111ac11111′.scan(“ab”).count
2
ywencn 2楼, 于24小时前回复 1.9.2p290 :001 >  ’11ab1111ab111ac11111′.count(‘ab’)
 => 5
楼主想表达什么?

ywencn 3楼, 于24小时前回复 哎呀。。。怎么python和ruby的count还不一样,哈哈

huacnlee 4楼, 于24小时前回复 Ruby 的 “”.count 统计的是后面所有的字符

dreamrise 5楼, 于24小时前回复 貌似_who还写过一个python与ruby转换的程序?

gaicitadie 6楼, 于23小时前回复 奥运奖牌榜:
国家 金牌数 银牌数 铜牌数
china 37 26 11
usa 30 22 50
russia 30 33 20

中国习惯上先按金牌数排名,金牌数一样的按银牌数再排,如果银牌数再一样就按铜牌数排:

>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:(-x[1],-x[2],-x[3]))
[('china', 37, 26, 11), ('russia', 30, 33, 20), ('usa', 30, 22, 50)]
美国习惯上金牌银牌铜牌都是奖牌,所以按奖牌总数排序:

>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:-(x[1]+x[2]+x[3]))
[('usa', 30, 22, 50), ('russia', 30, 33, 20), ('china', 37, 26, 11)]
python的排序达到了类似SQL查询的能力,只需要告诉它排序的条件就可以了,python为数据而生

gaicitadie 7楼, 于23小时前回复 上面的例子是python模拟SQL的order by功能,下面的例子用python模拟SQL的where条件查询

统计金牌数超过35的国家:

>>> [x for x in [('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)] if x[1]>35]
[('china', 37, 26, 11)]
统计奖牌总数超过100的国家:

>>> [x for x in [('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)] if x[1]+x[2]+x[3]>100]
[('usa', 30, 22, 50)]
huyong36 8楼, 于23小时前回复 @gaicitadie ruby是

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1] > 35}
[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1] + x[2] + x[3] > 100}
quakewang 9楼, 于23小时前回复 #6楼 @gaicitadie
order by 的ruby代码

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|m| [-m[1], -m[2], -m[3]]}
[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|m| -(m[1] + m[2] + m[3])]}
skandhas 10楼, 于23小时前回复 从楼主的例子直接翻译到Ruby
1 中国习惯上先按金牌数排名,金牌数一样的按银牌数再排,如果银牌数再一样就按铜牌数排:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|x| [-x[1],-x[2],-x[3]]}
2 美国习惯上金牌银牌铜牌都是奖牌,所以按奖牌总数排序:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|x| -(x[1]+x[2]+x[3])}
3 统计金牌数超过35的国家:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1] >35}
4 统计奖牌总数超过100的国家:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1]+x[2]+x[3] > 100}
这两个语言都挺类似,我觉得ruby的select更直观。

另 楼主这个帖子想表达什么?没看出什么来。如果说只通过sorted就说明python是为数据而生的话,那ruby不也是吗。哈哈

daqing 11楼, 于23小时前回复 我来写个Ruby版本的。

第一个,奖牌排序:

data = [[:china, 27, 26, 11], [:usa, 20, 22, 50], [:russia, 30, 33, 20]]

data.sort_by { |x| [-x[1], -x[2], -x[3]] } # 中国排序方法,按金/银/铜牌数
data.sort_by { |x| -(x[1] + x[2] + x[3]) } # 美国排序方法,按奖牌总数
第二个,奖牌统计:

data.select { |x| x[1] > 35 } # 金牌数超过35的国家
data.select { |x| x[1] + x[2] + x[3] > 100 } # 奖牌总数超过100的国家
哪个更简洁,一目了然了吧。

daqing 12楼, 于23小时前回复 原来大家都在回复。。等我写出来才发现。

daqing 13楼, 于23小时前回复 #10楼 @skandhas 看了你的方法,才想到,select是更直接的做法。collect方法会包含nil值。

reus 14楼, 于23小时前回复 Why I Hate Advocacy
http://www.perl.com/pub/2000/12/advocacy.html

gaicitadie 15楼, 于23小时前回复 总统选举投票,初步唱票记录:

['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
根据唱票记录统计每人的票数并按从多到少排序

>>> l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
>>> sorted(set([(i, l.count(i)) for i in l]), key=lambda x:-x[1])
[('Jim', 4), ('bush', 2), ('obama', 1)]
clearJiang 16楼, 于23小时前回复 #15楼 @gaicitadie 不如直接用collections.Counter

gaicitadie 17楼, 于23小时前回复 #16楼 @clearJiang 低版本没有collections

daqing 18楼, 于23小时前回复 总统选举投票

l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
l.uniq.collect { |x| [x, l.count(x)] }
=> [["Jim", 4], ["bush", 2], ["obama", 1]]
skandhas 19楼, 于22小时前回复 #15楼 @gaicitadie
根据唱票记录统计每人的票数并按从多到少排序:

l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
l.group_by{|i| i}.map{|k,v| [k,v.length] }
quakewang 20楼, 于22小时前回复 python要和ruby比 文件、字符操作或者数组、Hash操作的便利性绝对完败,要砸场还不如在性能上一棍子打死ruby。

bony 21楼, 于22小时前回复 这样的帖子应该多一点。长知识。@skandhas cool.

quakewang 22楼, 于22小时前回复 #15楼 @gaicitadie

['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama'].inject(Hash.new(0)) {|h, e| h[e] += 1; h}.sort_by{|e| -e[1]}
daqing 23楼, 于22小时前回复 说实话,Python的lambda匿名函数,跟Ruby的Block相比,从书写上就败了。

gaicitadie 24楼, 于22小时前回复 随机设置验证码的4个字符(不包括图片处理部分)

>>> import random
>>> s = ‘ABCDEFGHIJKLMNPRSTUVWXYZ’
>>> ”.join(random.sample((s),4))
‘EXSG’
>>> ”.join(random.sample((s),4))
‘TGYN’
>>> ”.join(random.sample((s),4))
‘MEYP’
>>> ”.join(random.sample((s),4))
‘TGIF’
>>> ”.join(random.sample((s),4))
‘JDWF’
quakewang 25楼, 于22小时前回复 #24楼 @gaicitadie

(‘A’..’Z’).to_a.sample(4).join
reus 26楼, 于22小时前回复 #15楼 @gaicitadie 你这个算法是O(n ^ 2)的,应该用reduce

def stat(acc, x):
  acc.setdefault(x, 0)
  acc[x] += 1
  return acc
sorted(reduce(stat,
  ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama'], {}).iteritems(),
    key = lambda x: -x[1])
huyong36 27楼, 于22小时前回复 @skandhas cool,加上个排序。

gaicitadie 28楼, 于22小时前回复 #26楼 @reus reduce不如列表解析快,虽然list.count会重复统计

skandhas 29楼, 于22小时前回复 #27楼 @huyong36
对,是忘了排序

l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
l.group_by{|i| i}.map{|k,v| [k,v.length] }.sort_by{|name,count| -count }
huacnlee 30楼, 于22小时前回复 风格不同而已,用起来都是一样方便。这个就是让我喜欢 Python 和 Ruby 的原因之一。

reus 31楼, 于22小时前回复 #28楼 @gaicitadie
就是慢在count调用上,for i in l遍历数组,且每个元素又再count遍历一次,O(n ^ 2)
reduce只需要遍历一次,O(n)
不信可以测试下

huyong36 32楼, 于22小时前回复 这帖应该是捧场帖,我喜欢这样的学习。

raecoo 33楼, 于22小时前回复 受用

hysios 34楼, 于21小时前回复 •字符串查找
# python
>>> ’11ab1111ab111ac11111′.count(‘ab’)
2
# Ruby
ruby-1.9.2-p290 >   ’11ab111123ab111ac11111′.count ‘ab’, ‘b’
2
hysios 35楼, 于21小时前回复 •奖牌排序
# python
>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:(-x[1],-x[2],-x[3]))
[('china', 37, 26, 11), ('russia', 30, 33, 20), ('usa', 30, 22, 50)]
# ruby
ruby-1.9.2-p290 > [['china',37,26,11], ['usa',30,22,50],['russia',30,33,20]].sort_by {|name,j,y,t| [-j,-y,-t] }
 => [["china", 37, 26, 11], ["russia", 30, 33, 20], ["usa", 30, 22, 50]]
hysios 36楼, 于21小时前回复 •奖牌统计
# python
>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:-(x[1]+x[2]+x[3]))
[('usa', 30, 22, 50), ('russia', 30, 33, 20), ('china', 37, 26, 11)]
# ruby
ruby-1.9.2-p290 > [['china',37,26,11], ['usa',30,22,50],['russia',30,33,20]].sort_by {|name,j,y,t| [-j + -y + -t] }
 => [["usa", 30, 22, 50], ["russia", 30, 33, 20], ["china", 37, 26, 11]]
kfll 37楼, 于21小时前回复 捧场..
js:

’11ab1111ab111ac11111′.match(/ab/g).length;
’11ab1111ab111ac11111′.split(‘ab’).length – 1;
中式排名:

[[37, 26, 11], [30, 22, 50], [30, 33, 20]].sort().reverse();
hysios 38楼, 于21小时前回复 总统选举投票,初步唱票记录:

# ruby
>>> l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
>>> sorted(set([(i, l.count(i)) for i in l]), key=lambda x:-x[1])
[('Jim', 4), ('bush', 2), ('obama', 1)]
# ruby
ruby-1.9.2-p290 >  ['bush','Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama'].each_with_object({}) {|name,s| s[name] = s.fetch(name,0) + 1 }.sort
 => [["Jim", 4], ["bush", 3], ["obama", 1]]
huyong36 39楼, 于21小时前回复 #34楼 @hysios

’11ab111123ab111ac11111′.count ‘ab’, ‘b’
这样不对吧…这样只是找出来字符串里出现b的次数。

irb(main):106:0> ’11ab111123ab111ac11111b’.count ‘ab’, ‘b’
=> 3
hysios 40楼, 于21小时前回复 @huyong36 thx count是没办法实现的, 别的方法也不错

huyong36 41楼, 于20小时前回复 #40楼 @hysios 恩,请教

irb(main):115:0> ’11ab111123ab111c11111′.count  ‘a’
=> 2
irb(main):114:0> ’11ab111123ab111c11111′.count  ‘ab’
=> 4
字符可以统计,为什么字符串不能。。

jhjguxin 42楼, 于20小时前回复 @huyong36
count([other_str]+) → fixnum click to toggle source
Each other_str parameter defines a set of characters to count. The intersection of these sets defines the characters to count in str. Any other_str that starts with a caret (^) is negated. The sequence c1–c2 means all characters between c1 and c2.

Guest 43楼, 于20小时前回复 gaicitadie = [['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].tap do |man|
  def man.make_self(&process); process.call self; end
  def man.become_egghead
    `python -c “print( sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:(-x[1],-x[2],-x[3])) )”`
  end
  def man.glow_up
    dont_be_shy = true
    unless self.respond_to? :more_elegant, dont_be_shy
      def self.more_elegant
        self.sort_by { |country, glods, silvers, bronzes| [-glods,-silvers,-bronzes] }
      end
    end
    if self.respond_to? :become_egghead
      class << self; remove_method :become_egghead; end
    end
    self
  end
end
gaicitadie.make_self &:become_egghead
gaicitadie.glow_up.make_self &:more_elegant
geekontheway 44楼, 于20小时前回复 #41楼 @huyong36 ruby的count 统计的是字符的数量 所以’11ab111123ab111c11111′.count ‘ab’等同于’11ab111123ab111c11111′.count ‘a’ + ’11ab111123ab111c11111′.count ‘b’

jhjguxin 45楼, 于20小时前回复 简而言之就是 取每一个字符的count的交集

huyong36 46楼, 于20小时前回复 @geekontheway @jhjguxin 3Q…

hysios 47楼, 于20小时前回复 #41楼 @huyong36 count 是统计所有的字符,并不会把参数当成字符串处理

FenRagwort 48楼, 于17小时前回复 合并两个字典/哈希,重复的项目,两个值相加

hash1.merge(hash2) {|dupkey,val1,val2| val1 + val2 }
楼主来个Python的写法?

hhuai 49楼, 于16小时前回复 method_missing, 楼主来个??

gaicitadie 50楼, 于14小时前回复 #48楼 @FenRagwort ,这个暂时只想到了普通方法

for k,v in hash2.items():
    if k in hash1:
        hash1[k] += v
    else:
        hash1.setdefault(k,v)
zw963 51楼, 于12小时前回复 #19楼 @skandhas

的确酷, 不说说实在的. group_by用来做这个, 真是有点大才小用了.

reus 52楼, 于12小时前回复 #49楼 @hhuai

class Foo:
  def __getattr__(self, name):
    def _foo(*arg, **kwargs):
      return self.method_missing(name, *arg, **kwargs)
    return _foo

  def method_missing(self, name, *args, **kwargs):
    print name, args, kwargs

a = Foo()
a.foo(‘bar’, baz = ‘baz’)

 

huacnlee 1楼, 于24小时前回复 irb> ’11ab1111ab111ac11111′.scan(“ab”).count
2
ywencn 2楼, 于24小时前回复 1.9.2p290 :001 >  ’11ab1111ab111ac11111′.count(‘ab’)
 => 5
楼主想表达什么?

ywencn 3楼, 于24小时前回复 哎呀。。。怎么python和ruby的count还不一样,哈哈

huacnlee 4楼, 于24小时前回复 Ruby 的 “”.count 统计的是后面所有的字符

dreamrise 5楼, 于24小时前回复 貌似_who还写过一个python与ruby转换的程序?

gaicitadie 6楼, 于23小时前回复 奥运奖牌榜:
国家 金牌数 银牌数 铜牌数
china 37 26 11
usa 30 22 50
russia 30 33 20

中国习惯上先按金牌数排名,金牌数一样的按银牌数再排,如果银牌数再一样就按铜牌数排:

>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:(-x[1],-x[2],-x[3]))
[('china', 37, 26, 11), ('russia', 30, 33, 20), ('usa', 30, 22, 50)]
美国习惯上金牌银牌铜牌都是奖牌,所以按奖牌总数排序:

>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:-(x[1]+x[2]+x[3]))
[('usa', 30, 22, 50), ('russia', 30, 33, 20), ('china', 37, 26, 11)]
python的排序达到了类似SQL查询的能力,只需要告诉它排序的条件就可以了,python为数据而生

gaicitadie 7楼, 于23小时前回复 上面的例子是python模拟SQL的order by功能,下面的例子用python模拟SQL的where条件查询

统计金牌数超过35的国家:

>>> [x for x in [('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)] if x[1]>35]
[('china', 37, 26, 11)]
统计奖牌总数超过100的国家:

>>> [x for x in [('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)] if x[1]+x[2]+x[3]>100]
[('usa', 30, 22, 50)]
huyong36 8楼, 于23小时前回复 @gaicitadie ruby是

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1] > 35}
[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1] + x[2] + x[3] > 100}
quakewang 9楼, 于23小时前回复 #6楼 @gaicitadie
order by 的ruby代码

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|m| [-m[1], -m[2], -m[3]]}
[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|m| -(m[1] + m[2] + m[3])]}
skandhas 10楼, 于23小时前回复 从楼主的例子直接翻译到Ruby
1 中国习惯上先按金牌数排名,金牌数一样的按银牌数再排,如果银牌数再一样就按铜牌数排:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|x| [-x[1],-x[2],-x[3]]}
2 美国习惯上金牌银牌铜牌都是奖牌,所以按奖牌总数排序:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].sort_by{|x| -(x[1]+x[2]+x[3])}
3 统计金牌数超过35的国家:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1] >35}
4 统计奖牌总数超过100的国家:

[['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].select{|x| x[1]+x[2]+x[3] > 100}
这两个语言都挺类似,我觉得ruby的select更直观。

另 楼主这个帖子想表达什么?没看出什么来。如果说只通过sorted就说明python是为数据而生的话,那ruby不也是吗。哈哈

daqing 11楼, 于23小时前回复 我来写个Ruby版本的。

第一个,奖牌排序:

data = [[:china, 27, 26, 11], [:usa, 20, 22, 50], [:russia, 30, 33, 20]]

data.sort_by { |x| [-x[1], -x[2], -x[3]] } # 中国排序方法,按金/银/铜牌数
data.sort_by { |x| -(x[1] + x[2] + x[3]) } # 美国排序方法,按奖牌总数
第二个,奖牌统计:

data.select { |x| x[1] > 35 } # 金牌数超过35的国家
data.select { |x| x[1] + x[2] + x[3] > 100 } # 奖牌总数超过100的国家
哪个更简洁,一目了然了吧。

daqing 12楼, 于23小时前回复 原来大家都在回复。。等我写出来才发现。

daqing 13楼, 于23小时前回复 #10楼 @skandhas 看了你的方法,才想到,select是更直接的做法。collect方法会包含nil值。

reus 14楼, 于23小时前回复 Why I Hate Advocacy
http://www.perl.com/pub/2000/12/advocacy.html

gaicitadie 15楼, 于23小时前回复 总统选举投票,初步唱票记录:

['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
根据唱票记录统计每人的票数并按从多到少排序

>>> l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
>>> sorted(set([(i, l.count(i)) for i in l]), key=lambda x:-x[1])
[('Jim', 4), ('bush', 2), ('obama', 1)]
clearJiang 16楼, 于23小时前回复 #15楼 @gaicitadie 不如直接用collections.Counter

gaicitadie 17楼, 于23小时前回复 #16楼 @clearJiang 低版本没有collections

daqing 18楼, 于23小时前回复 总统选举投票

l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
l.uniq.collect { |x| [x, l.count(x)] }
=> [["Jim", 4], ["bush", 2], ["obama", 1]]
skandhas 19楼, 于22小时前回复 #15楼 @gaicitadie
根据唱票记录统计每人的票数并按从多到少排序:

l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
l.group_by{|i| i}.map{|k,v| [k,v.length] }
quakewang 20楼, 于22小时前回复 python要和ruby比 文件、字符操作或者数组、Hash操作的便利性绝对完败,要砸场还不如在性能上一棍子打死ruby。

bony 21楼, 于22小时前回复 这样的帖子应该多一点。长知识。@skandhas cool.

quakewang 22楼, 于22小时前回复 #15楼 @gaicitadie

['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama'].inject(Hash.new(0)) {|h, e| h[e] += 1; h}.sort_by{|e| -e[1]}
daqing 23楼, 于22小时前回复 说实话,Python的lambda匿名函数,跟Ruby的Block相比,从书写上就败了。

gaicitadie 24楼, 于22小时前回复 随机设置验证码的4个字符(不包括图片处理部分)

>>> import random
>>> s = ‘ABCDEFGHIJKLMNPRSTUVWXYZ’
>>> ”.join(random.sample((s),4))
‘EXSG’
>>> ”.join(random.sample((s),4))
‘TGYN’
>>> ”.join(random.sample((s),4))
‘MEYP’
>>> ”.join(random.sample((s),4))
‘TGIF’
>>> ”.join(random.sample((s),4))
‘JDWF’
quakewang 25楼, 于22小时前回复 #24楼 @gaicitadie

(‘A’..’Z’).to_a.sample(4).join
reus 26楼, 于22小时前回复 #15楼 @gaicitadie 你这个算法是O(n ^ 2)的,应该用reduce

def stat(acc, x):
  acc.setdefault(x, 0)
  acc[x] += 1
  return acc
sorted(reduce(stat,
  ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama'], {}).iteritems(),
    key = lambda x: -x[1])
huyong36 27楼, 于22小时前回复 @skandhas cool,加上个排序。

gaicitadie 28楼, 于22小时前回复 #26楼 @reus reduce不如列表解析快,虽然list.count会重复统计

skandhas 29楼, 于22小时前回复 #27楼 @huyong36
对,是忘了排序

l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
l.group_by{|i| i}.map{|k,v| [k,v.length] }.sort_by{|name,count| -count }
huacnlee 30楼, 于22小时前回复 风格不同而已,用起来都是一样方便。这个就是让我喜欢 Python 和 Ruby 的原因之一。

reus 31楼, 于22小时前回复 #28楼 @gaicitadie
就是慢在count调用上,for i in l遍历数组,且每个元素又再count遍历一次,O(n ^ 2)
reduce只需要遍历一次,O(n)
不信可以测试下

huyong36 32楼, 于22小时前回复 这帖应该是捧场帖,我喜欢这样的学习。

raecoo 33楼, 于22小时前回复 受用

hysios 34楼, 于21小时前回复 •字符串查找
# python
>>> ’11ab1111ab111ac11111′.count(‘ab’)
2
# Ruby
ruby-1.9.2-p290 >   ’11ab111123ab111ac11111′.count ‘ab’, ‘b’
2
hysios 35楼, 于21小时前回复 •奖牌排序
# python
>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:(-x[1],-x[2],-x[3]))
[('china', 37, 26, 11), ('russia', 30, 33, 20), ('usa', 30, 22, 50)]
# ruby
ruby-1.9.2-p290 > [['china',37,26,11], ['usa',30,22,50],['russia',30,33,20]].sort_by {|name,j,y,t| [-j,-y,-t] }
 => [["china", 37, 26, 11], ["russia", 30, 33, 20], ["usa", 30, 22, 50]]
hysios 36楼, 于21小时前回复 •奖牌统计
# python
>>> sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:-(x[1]+x[2]+x[3]))
[('usa', 30, 22, 50), ('russia', 30, 33, 20), ('china', 37, 26, 11)]
# ruby
ruby-1.9.2-p290 > [['china',37,26,11], ['usa',30,22,50],['russia',30,33,20]].sort_by {|name,j,y,t| [-j + -y + -t] }
 => [["usa", 30, 22, 50], ["russia", 30, 33, 20], ["china", 37, 26, 11]]
kfll 37楼, 于21小时前回复 捧场..
js:

’11ab1111ab111ac11111′.match(/ab/g).length;
’11ab1111ab111ac11111′.split(‘ab’).length – 1;
中式排名:

[[37, 26, 11], [30, 22, 50], [30, 33, 20]].sort().reverse();
hysios 38楼, 于21小时前回复 总统选举投票,初步唱票记录:

# ruby
>>> l = ['Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama']
>>> sorted(set([(i, l.count(i)) for i in l]), key=lambda x:-x[1])
[('Jim', 4), ('bush', 2), ('obama', 1)]
# ruby
ruby-1.9.2-p290 >  ['bush','Jim', 'bush', 'Jim', 'Jim', 'Jim', 'bush', 'obama'].each_with_object({}) {|name,s| s[name] = s.fetch(name,0) + 1 }.sort
 => [["Jim", 4], ["bush", 3], ["obama", 1]]
huyong36 39楼, 于21小时前回复 #34楼 @hysios

’11ab111123ab111ac11111′.count ‘ab’, ‘b’
这样不对吧…这样只是找出来字符串里出现b的次数。

irb(main):106:0> ’11ab111123ab111ac11111b’.count ‘ab’, ‘b’
=> 3
hysios 40楼, 于21小时前回复 @huyong36 thx count是没办法实现的, 别的方法也不错

huyong36 41楼, 于20小时前回复 #40楼 @hysios 恩,请教

irb(main):115:0> ’11ab111123ab111c11111′.count  ‘a’
=> 2
irb(main):114:0> ’11ab111123ab111c11111′.count  ‘ab’
=> 4
字符可以统计,为什么字符串不能。。

jhjguxin 42楼, 于20小时前回复 @huyong36
count([other_str]+) → fixnum click to toggle source
Each other_str parameter defines a set of characters to count. The intersection of these sets defines the characters to count in str. Any other_str that starts with a caret (^) is negated. The sequence c1–c2 means all characters between c1 and c2.

Guest 43楼, 于20小时前回复 gaicitadie = [['china',37,26,11], ['usa',30,22,50], ['russia',30,33,20]].tap do |man|
  def man.make_self(&process); process.call self; end
  def man.become_egghead
    `python -c “print( sorted([('china',37,26,11), ('usa',30,22,50), ('russia',30,33,20)], key=lambda x:(-x[1],-x[2],-x[3])) )”`
  end
  def man.glow_up
    dont_be_shy = true
    unless self.respond_to? :more_elegant, dont_be_shy
      def self.more_elegant
        self.sort_by { |country, glods, silvers, bronzes| [-glods,-silvers,-bronzes] }
      end
    end
    if self.respond_to? :become_egghead
      class << self; remove_method :become_egghead; end
    end
    self
  end
end
gaicitadie.make_self &:become_egghead
gaicitadie.glow_up.make_self &:more_elegant
geekontheway 44楼, 于20小时前回复 #41楼 @huyong36 ruby的count 统计的是字符的数量 所以’11ab111123ab111c11111′.count ‘ab’等同于’11ab111123ab111c11111′.count ‘a’ + ’11ab111123ab111c11111′.count ‘b’

jhjguxin 45楼, 于20小时前回复 简而言之就是 取每一个字符的count的交集

huyong36 46楼, 于20小时前回复 @geekontheway @jhjguxin 3Q…

hysios 47楼, 于20小时前回复 #41楼 @huyong36 count 是统计所有的字符,并不会把参数当成字符串处理

FenRagwort 48楼, 于17小时前回复 合并两个字典/哈希,重复的项目,两个值相加

hash1.merge(hash2) {|dupkey,val1,val2| val1 + val2 }
楼主来个Python的写法?

hhuai 49楼, 于16小时前回复 method_missing, 楼主来个??

gaicitadie 50楼, 于14小时前回复 #48楼 @FenRagwort ,这个暂时只想到了普通方法

for k,v in hash2.items():
    if k in hash1:
        hash1[k] += v
    else:
        hash1.setdefault(k,v)
zw963 51楼, 于12小时前回复 #19楼 @skandhas

的确酷, 不说说实在的. group_by用来做这个, 真是有点大才小用了.

reus 52楼, 于12小时前回复 #49楼 @hhuai

class Foo:
  def __getattr__(self, name):
    def _foo(*arg, **kwargs):
      return self.method_missing(name, *arg, **kwargs)
    return _foo

  def method_missing(self, name, *args, **kwargs):
    print name, args, kwargs

a = Foo()
a.foo(‘bar’, baz = ‘baz’)

 

Francis.J(864248765)  13:19:50
>>> l=['a','a','b','b','b','c','c']

>>> sorted(set([i for i in l]))
['a', 'b', 'c']
Francis.J(864248765)  13:20:01
这样还行
Francis.J(864248765)  13:21:15
但是感觉 没有 pop 省资源
GG(75865965)  13:26:39
cat cat source.txt |uniq

Posted in Uncategorized

Helper Antipatterns

Helper AntiPatterns

Helper (輔助方法)的存在目的是用來輔助整理 View 中內嵌的複雜 Ruby 程式碼。設計得當的 Helper 可以加速專案的開發,以及增進程式的可讀性。然而,設計不好的 Helper 卻可能造成嚴重的反效果。

以下列舉常見的幾種糟糕的 Helper 設計模式:

1. 矯往過正:用 Helper 作 partial 該做的事

開發者以為 partial 效率是低下的,刻意不使用 partial,而改用 Helper 完成所有的動作:將需要重複使用的 HTML 通通寫成了 Ruby code,串接成 HTML:
def show_index_block(block_name, post, is_show_game)

block_title = content_tag(:h3, block_name)
section_header = content_tag(:div, block_title, :class => “section-header”)

game_name = is_show_game ? “【 #{post.games.first.name} 】” : “”
title = content_tag(:h4, link_to(“#{game_name} #{post.title}”, post_path(post)))
image = content_tag(:div, render_post_image(post), :class => “thumbnail”)
content = content_tag(:p, truncate( post.content, :length => 100))
section_content = content_tag(:div, “#{title}#{image}#{content}”, :class => “section-content”)

section_footer = content_tag(:div, link_to(“閱讀全文”, post_path(post)), :class => “section-footer”)

return content_tag(:div, “#{section_header}#{section_content}#{section_footer}” , :class => “article-teaser”)
end
 Helper 的作用只是協助整理 HTML 中的邏輯程式碼。若有大片 HTML 需要重複使用,應當需要利用 partial 機制進行 HTML 的重複利用。這樣的寫法,非但效率低下(可以用 HTML 產生,卻使用 Ruby 呼叫 Tag Helper,且製造大量 Ruby Object),且嚴重降低程式的可讀性,其他維護者將難以對這樣的 DOM 進行後續的維護翻修。

 

 
2. 容易混淆:在 Helper 裡面穿插 HTML tag

這也是另外一個矯枉過正的例子,不過方向剛好相反:「因為覺得使用 Ruby code 產生 HTML tag 可能浪費效能,而直接插入 HTML 在 Helper 裡面與 Ruby Code 混雜。」也造成了專案維護上的困難:因為 Ruby 中的字串是使用雙引號”,而 HTML 也是使用雙引號”,,所以就必須特別加入 ” 跳脫,否則就可能造成 syntax error。
錯誤
def post_tags_tag(post, opts = {})
# ….
raw tags.collect { |tag| “#{tag}” }.join(“, “)
end
大量的 ” 混雜在程式碼裡面,嚴重造成程式的可閱讀性,而且發生 syntax error 時難以 debug。
def post_tags_tag(post, opts = {})
# ….
raw tags.collect { |tag| “#{tag}” }.join(“, “)
end
即便換成 ‘ 單引號,狀況並沒有好上多少。
def post_tags_tag(post, opts = {})
# …
raw tags.collect { |tag| link_to(tag,posts_path(:tag => tag)) }.join(“, “)
end
正確的作法應該是妥善使用 Rails 內建的 Helper,使 Helper 裡面維持著都是 Ruby code 的狀態,並且具有高可讀性。

3. 強耦合:把 CSS 應該做的事綁在 Ruby Helper 上。

錯誤
def red_alert(message)
return content_tag(:span,message, :style => “font-color: red;”)
end

def green_notice(message)
return content_tag(:span,message, :style => “font-color: green;”)
end
開發者不熟悉 unobtrusive 的設計手法,直接就把 design 就綁上了 Ruby Helper。將來設計上若需要變更時,難以修改或擴充。
正確
def stickies(message, message_type)
content_tag(:span,message, :class => message_type.to_sym)
end

Please Login!!
樣式應該由 CSS 決定,使用 CSS class 控制,而非強行綁在 Helper 上。
4. 重複發明輪子

Rails 已內建許多實用 Helper,開發者卻以較糟的方式重造輪子。在此舉幾個比較經典的案例:

cycle
如何設計 table 的雙色列效果?

<% count = 0 > <table> <% @items.each do |item| %> <% if count % 2 == 0 %> <% css_class = “even “%> <% else %> <% css_class = “odd” %> <% end %> <tr class=”<%= css_class %>”> <td>item</td> </tr> <% count += 1%> <% end %> </table>

一般的想法會是使用兩種不同 CSS class : even 與 odd,著上不同的顏色。

<table> <% @items.each_with_index do |item, count| %> <% if count % 2 == 0 %> <% css_class = “even “%> <% else %> <% css_class = “odd” %> <% end %> <tr class=”<%= css_class %>”> <td>item</td> </tr> <% count += 1%> <% end %> </table>

這是一般粗心者會犯的錯誤。實際上 Ruby 的 Array 內建 each_with_index,不需另外宣告一個 count。

<table> <% @items.each_with_index do |item, count| %> <% if count % 2 == 0 %> <% css_class = “even “%> <% else %> <% css_class = “odd” %> <% end %> <tr class=”<%= css_class %>”> <td>item</td> </tr> <% count += 1%> <% end %> </table>

但其實還有更簡便的方法:Rails 內建了 cycle 這個 Helper。所以只要這樣寫就好了…

<table> <% @items.each do |item| %> <trodd”, “even”) %>”> <td>item</td> </tr> <% end %> </table>

常用你可能不知道的 Helper

限於篇幅,直接介紹幾個因為使用機率高,所以很容易被重造輪子的 Helper。開發者會寫出的相關 AntiPattern 部分就跳過了。

#TODO: examples

5. Tell, dont ask

這也是在 View 中會常出現的問題,直接違反了 Law of Demeter 原則,而造成了效能問題。十之八九某個 View 緩慢無比,最後抓出來背後幾乎都是這樣的原因。

不少開發者會設計出這樣的 helper:

 
def post_tags_tag(post, opts = {})
tags = post.tags
tags.collect { |tag| link_to(tag,posts_path(:tag => tag)) }.join(“, “)
end

這種寫法會造成在 View 中,執行迴圈時,造成不必要的大量 query (n+1),以及在 View 中製造不確定數量的大量物件。View 不僅效率低落也無法被 optimized。
def post_tags_tag(post, tags, opts = {})
tags.collect { |tag| link_to(tag,posts_path(:tag => tag)) }.join(“, “)
end

def index
@posts = Post.recent.includes(:tags)
end
正確的方法是使用 Tell, dont ask 原則,主動告知會使用的物件,而非讓 Helper 去猜。並配合 ActiveRecord 的 includes 減少不必要的 query( includes 可以製造 join query ,一次把需要的 posts 和 tags 撈出來)。

且在 controller query 有 object cache 效果,在 view 中則無。

小結

Helper 是 Rails Developer 時常在接觸的工具。但可惜的是,多數開發者卻無法將此利器使得稱手,反而造成了更多問題。在我所曾經參與的幾十個 Rails 專案中,很多設計和效能問題幾乎都是因為寫的不好的 View / Helper 中的 slow query 或伴隨產生的大量 object 所造成的 memory bloat 導致的。但參與專案的開發者並沒有那麼多的經驗,能夠抓出確切的病因,卻都將矛頭直接是 Rails 的效能問題,或者是沒打上 Cache 的關係。這樣的說法只是把問題掩蓋起來治標,而非治本。

下次若有遇到 performance issue,請先往 View 中瞧看看是不是裡面出現了問題。也許你很快就可以找到解答。

Posted by xdite Jan 12th, 2012

Posted in Uncategorized

factory_girl Validation failed

You need to use a sequence to prevent the creation of user objects with the same email, since you must have a validation for the uniqueness of emails in your User model.

Factory.sequence :email do |n|
  “test#{n}@example.com”
end

Factory.define :user do |user|
  user.name "Testing User"
  user.email { Factory.next(:email) }
  user.password "foobar"
  user.password_confirmation "foobar"
end

You can read more in the Factory Girl documentation.

 

Using factory_girl to create several instances of a class that belongs to another class causes a Validation failed error.

This happens because each instance tries to automatically create the object to which it belongs. However since the first instance creates it, the following instances crash because the object already exists.

I have been struggling to solve this problem and it seems finally I arrived to a satisfactory solution.

The problem arises when there is a one to many relationship between to classes and I try to create several instances of a class.

In my case I have a subdomain which has many users:

class Subdomain < ActiveRecord::Base validates_uniqueness_of :name, :case_sensitive => false
has_many :users
end
class User < ActiveRecord::Base belongs_to: subdomain endThe factories are as follows: FactoryGirl.define do factory :subdomain do name ‘test-subdomain’ end factory :user do subdomain email ‘test-user@example.com’ password ‘123456¿ password_confirmation ‘123456’ end endWhen I try to create two users using the following code: FactoryGirl.create(:user, :email => “first@example.com”)
FactoryGirl.create(:user, :email => “second@example.com”)I get the following error:

Validation failed: Name has already been taken (ActiveRecord::RecordInvalid)This happens because when the first user is created, the default subdomain is created too and when the second user is created the subdomain already exists.

If we want to use the same subdomain for both users we can do the following:

s = FactoryGirl.create(:subdomain)
FactoryGirl.create(:user, :email => “first@example.com”, :subdomain => s)
FactoryGirl.create(:user, :email => “second@example.com”, :subdomain => s)However as our has_many relations become deeper, test data creation becomes more complex.

My solution to this problem is as to change the factory for user:

factory :user do
subdomain { Subdomain.find_by_name(‘test-subdomain’) || FactoryGirl.create(:subdomain) }
email ‘test-user@example.com’
password ‘123456’
password_confirmation ‘123456’
endIn this case the factory uses the default subdomain if it already exists, avoiding the validation problem.

Now if we use the initial code, it works without problem, assigning both users to the default subdomain

FactoryGirl.create(:user, :email => “first@example.com”)
FactoryGirl.create(:user, :email => “second@example.com”)However this does not limit us to use the same subdomain for all users:

other_subdomain = FactoryGirl.create(:subdomain, :name => “other-subdomain”)

FactoryGirl.create(:user, :email => “first@example.com”, :subdomain => other_subdomain)
FactoryGirl.create(:user, :email => “second@example.com”)In this case, the first user is assigned to other-subdomain and the second user is assigned to test-subdomain.

Posted in Uncategorized

TomDoc for Ruby – Version 1.0.0-rc1

Purpose
TomDoc is a code documentation specification that helps you write precise documentation that is nice to read in plain text, yet structured enough to be automatically extracted and processed by a machine.

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

Method Documentation
A quick example will serve to best illustrate the TomDoc method documentation format:

# Public: Duplicate some text an arbitrary number of times.
#
# text – The String to be duplicated.
# count – The Integer number of times to duplicate the text.
#
# Examples
#
# multiplex(‘Tom’, 4)
# # => ‘TomTomTomTom’
#
# Returns the duplicated String.
def multiplex(text, count)
text * count
end
TomDoc for a specific method consists of a block of single comment markers (#) that appears directly above the method. There SHOULD NOT be a blank line between the comment block and the method definition. A TomDoc method block consists of five optional sections: a description section, an arguments section, a yields section, an examples section, a returns section, and a signature section. Lines that contain text MUST be separated from the comment marker by a single space. Lines that do not contain text SHOULD consist of just a comment marker (no trailing spaces).

The Description Section
The description section SHOULD be in plain sentences. Each sentence SHOULD end with a period. Good descriptions explain what the code does at a high level. Make sure to explain any unexpected behavior that the method may have, or any pitfalls that the user may experience. Paragraphs SHOULD be separated with blank lines. Code within the description section should be indented three spaces from the starting comment symbol. Lines SHOULD be wrapped at 80 characters.

To describe the status of a method, you SHOULD use one of several prefixes:

Public: Indicates that the method is part of the project’s public API. This annotation is designed to let developers know which methods are considered stable. You SHOULD use this to document the public API of your project. This information can then be used along with Semantic Versioning to inform decisions on when major, minor, and patch versions should be incremented.

# Public: Initialize a new Widget.
Internal: Indicates that the method is part of the project’s internal API. These are methods that are intended to be called from other classes within the project but not intended for public consumption. For example:

# Internal: Normalize the filename.
Deprecated: Indicates that the method is deprecated and will be removed in a future version. You SHOULD use this to document methods that were Public but will be removed at the next major version.

# Deprecated: Resize an object to the given dimensions.
An example description that includes all of these elements might look something like the following.

# Public: Format some data with the given format. Possible format
# identifiers include:
#
# %i – Output the Integer i.
# %f.n – Output a Float f with n decimal places rounded.
#
# The format String may include any text. To escape a percent sign, prefix
# it with a backslash:
#
# “The sale price was %f.n% off retail.”
The Arguments Section
The arguments section consists of a list of arguments. Each list item MUST be comprised of the name of the argument, a dash, and an explanation of the argument in plain sentences. The expected type (or types) of each argument SHOULD be clearly indicated in the explanation. When you specify a type, use the proper classname of the type (for instance, use ‘String’ instead of ‘string’ to refer to a String type). If the argument has other constraints (e.g. duck-typed method requirements), simply state those requirements. The dashes following each argument name SHOULD be lined up in a single column. Lines SHOULD be wrapped at 80 columns. If an explanation is longer than that, additional lines MUST be indented at least two spaces but SHOULD be indented to match the indentation of the explanation. For example:

# element – The Symbol representation of the element. The Symbol should
# contain only lowercase ASCII alpha characters.
An argument that is String-like might look like this:

# actor – An object that responds to to_s. Represents the actor that
# will be output in the log.
All arguments are assumed to be required. If an argument is optional, you MUST specify the default value:

# host – The String hostname to bind (default: ‘0.0.0.0’).
For hash arguments, you SHOULD enumerate each valid option in a way similar to how normal arguments are defined:

# options – The Hash options used to refine the selection (default: {}):
# :color – The String color to restrict by (optional).
# :weight – The Float weight to restrict by. The weight should
# be specified in grams (optional).
Ruby allows for some interesting argument capabilities. In those cases, try to explain what’s going on as best as possible. Examples are a good way to demonstrate how methods should be invoked. For example:

# Print a log line to STDOUT. You can customize the output by specifying
# a block.
#
# msgs – Zero or more String messages that will be printed to the log
# separated by spaces.
# block – An optional block that can be used to customize the date format.
# If it is present, it will be sent a Time object representing
# the current time. Your block should return a String version of
# the time, formatted however you please.
#
# Examples
#
# log(“An error occurred.”)
#
# log(“No such file”, “/var/log/server.log”) do |time|
# time.strftime(“%Y-%m-%d %H:%M:%S”)
# end
#
# Returns nothing.
def log(*msgs, &block)

end
The Yields Section
The yields section is used to specify what is sent to the implicitly given block. The section MUST start with the word “Yields” and SHOULD contain a description and type of the yielded object. For example:

# Yields the Integer index of the iteration.
Lines SHOULD be wrapped at 80 columns. Wrapped lines MUST be indented under the above line by at least two spaces.

The Examples Section
The examples section MUST start with the word “Examples” on a line by itself. The next line SHOULD be blank. The following lines SHOULD be indented by two spaces (three spaces from the initial comment marker) and contain code that shows off how to call the method and (optional) examples of what it returns. Everything under the “Examples” line should be considered code, so make sure you comment out lines that show return values. For example:

# Examples
#
# multiplex(‘x’, 4)
# # => ‘xxxx’
#
# multiplex(‘apple’, 2)
# # => ‘appleapple’
The Returns/Raises Section
The returns section should explain in plain sentences what is returned from the method. The line MUST begin with “Returns”. If only a single thing is returned, state the nature and type of the value. For example:

# Returns the duplicated String.
If several different types may be returned, list all of them. For example:

# Returns the given element Symbol or nil if none was found.
If the return value of the method is not intended to be used, then you should simply state:

# Returns nothing.
If the method raises exceptions that the caller may be interested in, add additional lines that explain each exception and under what conditions it may be encountered. The lines MUST begin with “Raises”. For example:

# Returns nothing.
# Raises Errno::ENOENT if the file cannot be found.
# Raises Errno::EACCES if the file cannot be accessed.
Lines SHOULD be wrapped at 80 columns. Wrapped lines MUST be indented under the above line by at least two spaces. For example:

# Returns the atomic mass of the element as a Float. The value is in
# unified atomic mass units.
The Signature Section
The signature section allows you specify the nature of methods that are dynamically created at runtime.

The section MUST start with the word “Signature” on a line by itself. The next line SHOULD be blank. The following lines SHOULD be indented by two spaces (three spaces from the initial comment marker) and contain special code that shows the method signature(s). For complex dynamic signatures, you SHOULD name and demarcate signature variables with <> for required parts and [] for optional parts. Use … for repeating elements. If there are dynamic elements to the signature, document them in the same was as the Arguments section, but leave out any type declarations. Documentation for metaprogrammed methods may exist independent of any actual code, or it may appear above the code that creates the methods. Use your best judgment.

# Signature
#
# find_by_[_and_...](args)
#
# field – A field name.
Because metaprogrammed methods may be difficult to decipher, it’s best to include an examples section to demonstrate proper usage. For example:

# Public: Find Records by a specific field name and value. This method
# will be available for each field defined on the record.
#
# args – The value or Array of values of the field(s) to find by.
#
# Examples
#
# find_by_name_and_email(“Tom”, “tom@mojombo.com”)
#
# Returns an Array of matching Records.
#
# Signature
#
# find_by_[_and_...](args)
#
# field – A field name.
Class/Module Documentation
TomDoc for classes and modules follows the same form as Method Documentation but only contains the Description and Examples sections.

# Public: Various methods useful for performing mathematical operations.
# All methods are module methods and should be called on the Math module.
#
# Examples
#
# Math.square_root(9)
# # => 3
module Math

end
Just like methods, classes may be marked as Public, Internal, or Deprecated depending on their intended use.

Constants Documentation
Constants should be documented with freeform comments. The type of the constant and any important constraints should be stated.

# Public: Integer number of seconds to wait before connection timeout.
CONNECTION_TIMEOUT = 60
Just like methods, constants may be marked as Public, Internal, or Deprecated depending on their intended use.

Special Considerations
Constructor
A Ruby class’s initialize method does not have a significant return value. You MAY exclude the returns section. A larger description of the purpose of this class should be done at the Class level.

# Public: Initialize a Widget.
#
# name – A String naming the widget.
def initialize(name)

end
Attributes
Ruby’s built in attr_reader, attr_writer, and attr_accessor require a bit more consideration. With TomDoc you SHOULD document each of these method generators separately. Because each part of a method documentation section is optional, you can write concise yet unambiguous docs.

Here is an example TomDoc for attr_reader.

# Public: Returns the String name of the user.
attr_reader :name
Here is an example TomDoc for attr_writer.

# Public: Sets the String name of the user.
attr_writer :name
For attr_accessor you can use an overloaded shorthand that documents the getter and setter simultaneously:

# Public: Gets/Sets the String name of the user.
attr_accessor :name

Posted in Uncategorized