gem install rspec
rspec --init
我们可以用 .rspec
文件做 rspec 的配置。
--color
--format documentation
这里的 documentation
可以让 rspec 显示出具体的信息,而默认的是
--format progress
只会显示类似 testunit
的显示形式。
rails new *application* --skip-test-unit
可以让 rails 不要给予 test-unit 的任何内容。 然后在 Gemfile 添加
group :development, :test do
gem 'rspec-rails'
end
然后
rails generate rspec:install
之后如果执行rails g scaffold
那么就会在spec
目录下建立相应的测试。
group :development, :test do
gem 'rspec-rails'
gem 'rb-fsevent', :require => false if RUBY_PLATFORM =~ /darwin/i
gem 'guard-rspec'
gem 'guard-livereload'
end
安装 guard 的支持非常的简单。然后
guard init rspec
guard init livereload
guard
对于还没有想好测试内容的情况这个就是超级有用了。
首先可以这样做
describe Hotel do
it "should have method price"
end
或者这样
describe Hotel do
it "should have method price" do
pending
end
end
zombie = Zombie.new (name: 'Ash')
zombie.name.should == 'Ash'
zombie.should respond_to(:name)
zombie.weapons.should include(weapon)
zombie.weapon.should_not be_nil
最近又写 python 了,感觉好久不写又手生了。用 mysql 导数据,记下点东西吧。
在安装 pip 之前需要执行
apt-get install libmysqlclient-dev python-dev
要想让 mysql 很好的支持中文,在创建 table 的时候就要小心了。看了一下 ruby migration 生成的 sql table 是这个样子的:
CREATE TABLE `projects` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`description` text COLLATE utf8_unicode_ci,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`user_id` int(11) DEFAULT NULL,
`is_archived` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `index_projects_on_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
注意最下面的
ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
是一定要加的。
python 2 3 分离确实是个很让人揪心的事情。虽说 python3 已经对于 unicode 做了很好的支持,但是可惜 python3 一直发展不起来。我还是要苦逼的用着 python2.7 每次对于 string 都要自己去做一下转换。在把 string 扔给 MySQLdb 之前都要搞成 unicode 的。
通常在 linux 系统中的默认编码是 'ascii' 这导致 urllib2.urlopen().read()
出来的结果会有一些问题。
reload(sys)
sys.setdefaultencoding('utf-8')
这样会避免很多问题。
然后 HOWTO UNICODE 对于编码问题讲的非常的透彻。
MySQLdb 的一个 connection 是不支持多线程的。要想支持多线程,需要对每一个线程建立 connection。
在 /etc/mysql/my.cnf
里面有一个 bind_network 如果允许远程连接的话,一定不能是 127.0.0.1
。
然后就是给用户提升权限,让他可以 remote 连接。
grant all on *.* to adminm@'%' identified by '123456'
TINYBLOB, TINYTEXT L + 1 bytes, where L < 2^8 (255 Bytes)
BLOB, TEXT L + 2 bytes, where L < 2^16 (64 Kilobytes)
MEDIUMBLOB, MEDIUMTEXT L + 3 bytes, where L < 2^24 (16 Megabytes)
LONGBLOB, LONGTEXT L + 4 bytes, where L < 2^32 (4 Gigabytes)
text 最多支持 16K。
如果想要给 text 字段建立索引那就需要指定索引的长度。
CREATE UNIQUE INDEX index_name ON misc_info (key(10));
UPDATE: 我后来木有这么做了,我对 url 做了 md5 这样我就有了一个长度为 32 的十六进制字符串。我对 md5 做了索引。
这个问题也困扰了我好久。先描述一下,大概是因为 mysql 的连接有一个最长的连接时间。然后由于爬虫需要长时间的连接或者是等待连接,因此会导致在某些时候这个连接就断开了。
先去 /etc/mysql/my.cnf 看一些所有有关 timeout
的参数。
connect_timeout = 10
wait_timeout = 180
net_read_timeout = 30
net_write_timeout = 30
这里的时间单位都是秒,我查了一下资料,有对这些参数的具体解释,在这里
connect_timeout
在很多地方都存在,就是连接 mysql 时候的超时时间。应该不是这个。
wait_timeout
在连接建立之后 mysql 等待一个连接有动作的时间。也就是说如果连接在这个时间之内没有动作就会断开连接了。
即使连接没有处于 sleep 状态,即客户端忙于计算或者存储数据,MySQL 也选择了有条件的等待。在数据包的分发过程中,客户端可能来不及响应(发送、接收、或者处理数据包太慢)。为了保证连接不被浪费在无尽的等待中,MySQL 也会选择有条件(net_read_timeout 和 net_write_timeout)地主动断开连接。
这就让我纠结了,我尝试了修改以上的参数却没有从根本上解决这个问题。最后我就采用了比较暴力的方式。
def execute(self, *args, **kvargs):
try:
cursor = self.conn.cursor()
cursor.execute(*args, **kvargs)
except (AttributeError, MySQLdb.OperationalError):
self.connect()
cursor = self.conn.cursor()
cursor.execute(*args, **kvargs)
return cursor
哈,就是如果断开,我就重连...
这个解决的不太好,但是确实有效。
select url from taobao limit 1 offset 2000000;
这条语句在我有 300w 的表里要跑个十几秒... explain 如下:
mysql> explain select url from taobao limit 1 offset 2000000;
+---------------+------+---------+------+---------+-------+
| possible_keys | key | key_len | ref | rows | Extra |
|---------------|------|---------|------|---------|-------|
| NULL | NULL | NULL | NULL | 3298171 | |
+---------------+------+---------+------+---------+-------+
换一种方式
mysql> explain select url from taobao where id < 2000001 and id >= 2000000;
+---------------+---------+---------+------+------+-------------+
| possible_keys | key | key_len | ref | rows | Extra |
+---------------+---------+---------+------+------+-------------+
| PRIMARY | PRIMARY | 4 | NULL | 1 | Using where |
+---------------+---------+---------+------+------+-------------+
0.05 秒的速度。
最近有一个诡异的需求,需要做一个多对多的图关系。情况是这样的,有一堆本来是扁平关系的标签,现在需要给他们组织出来层级关系了。那么一个 tag 就会有很多的 父节点 以及 子节点。那么,简单来看,其实就是一个自身元素的多对多关系了。
通常的,针对两个 model 的多对多关系是这样的。link here
class Physician < ActiveRecord::Base
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ActiveRecord::Base
belongs_to :physician
belongs_to :patient
end
class Patient < ActiveRecord::Base
has_many :appointments
has_many :physicians, through: :appointments
end
而对于通常的,对于自身做树级关系的 model 如下: link here
class Employee < ActiveRecord::Base
has_many :subordinates, class_name: "Employee",
foreign_key: "manager_id"
belongs_to :manager, class_name: "Employee"
end
那么,我现在所需要的差不多就是把这两个结合一下。
class Word < ActiveRecord::Base
has_many :parent_relations, class_name: :WordRelation, foreign_key: :child_id
has_many :child_relations, class_name: :WordRelation, foreign_key: :parent_id
has_many :parents, through: :parent_relations
has_many :children, through: :child_relations
end
class WordRelation < ActiveRecord::Base
attr_accessible :child_id, :parent_id, :parent, :child
belongs_to :parent, class_name: :Word
belongs_to :child, class_name: :Word
end
两个 model word
以及 word_relation
。对于这种 self join 的关系,通常是不能按照默认的外键的。那么就像第二个例子一样。我们需要自己指定 foreign_key
。这里有个比较特别的地方。
has_many :parent_relations, class_name: :WordRelation, foreign_key: :child_id
parent_relations
需要的外键居然是 child_id
感觉有点奇怪吧。不过理清 activerecord 帮你生成的 sql 是什么样子就明白了。为了找其父亲节点,那么 sql 语句大概如下:
select * from word_relations where [one column] = '[this word id]'
要找父亲节点,那么 where 中就是找 哪个节点的子节点是这个 word。所以就应当是反着的才对的。
做了上述的工作之后,一个图状的 word 关系就可以搞定了。