curry 和数学中定义各种符号一样,主要是用来抽取公用部分,简化代码。
比如高中数学中的累加符号Σ
对应到 Ruby 代码,我们可以定义一个 sigma lambda
sigma = -> (f, a, b) { a.upto(b).map{|n| f.(n)}.inject(:+)}
然后用 curry 定义数字累加操作和平方累加操作:
sum_of_number = sigma.curry.(-> (n) {n})
sum_of_square = sigma.curry.(-> (n) {n * n})
sum_of_number.(1,10)
sum_of_square.(1,10)
可以用相同的代码来定义累乘符号∏
pi = -> (f, a, b) { a.upto(b).map{|n| f.(n)}.inject(:*)}
更进一步,Σ和∏都是范围操作,我们可以用 curry 抽取出来:
range = -> (x, f, a, b) { x.(a.upto(b).map{|n| f.(n)})}
sigma = range.curry.(-> (r) {r.inject(:+)})
pi = range.curry.(-> (r) {r.inject(:*)})
products_of_number = pi.curry.(-> (n) {n})
products_of_number.(1,10)
贴一下我之前给一个类似项目做的性能优化,单机目标 500RPS 跑 wrk 本机测试,单机结果 1105RPS, 这是在一台每月 200 元的 2 核 4GB 最低配云主机跑的结果:
10 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 8.95ms 1.59ms 54.36ms 82.69%
Req/Sec 224.23 142.93 484.00 79.00%
11171 requests in 10.10s, 3.05MB read
Requests/sec: 1105.64
Transfer/sec: 309.35KB
你要问什么架构?基于 rails-api,redis 存储,都是大路货,没什么高端科技 150 台机器...只能说楼主有钱,请我!每小时仅收费$300,保证赚回你的机器钱
上传大文件和下载一样,可以让 nginx 来负责接收上传的文件,然后 rack 通过 header 从文件系统读取上传完毕的文件:
https://stackoverflow.com/questions/44371643/nginx-php-failing-with-large-file-uploads-over-6-gb
我现在用的 Intel NUC
Ubuntu 17.04 物理机 希望有个命令行就好了
看了一下 README,counter_culture 是通过把更新计数器移到 after_commit 解决的,也算一种绕过去的方法吧
他们不但没有做类型检查,反倒是去改变语法
Javascript 是因为语言本身设计缺陷,所以才需要检查传入的是否是 function,Ruby 已经声明这是一个 blcok,你不可能给这个方法传入第二个参数,完全没必要进行参数类型检查,常见的只是用 block_gvien?检查一下是否有 block:
class Foo
def bar(name, &block)
str = "Hello #{name}"
yield str if block_given?
end
end
foo = Foo.new
# block是可选的:
foo.bar('world') do |str|
puts str
end
foo.bar('ruby')
如果你没有认真学过 Ruby 这门语言,或者只是扫一眼浏览式学习,你根本不知道 yield 做了什么。
对于没有认真学习又 blahblah 的人,最好的回复是:RTFM
我去掉了 &b1, &b2, &b3,看看可读性如何,在你看 obj.m1 的时候,你知道 yield 传入了什么吗?看 obj.m2 的时候,或者本来就是从 obj.m2 看起,这时候你肯定会不知道 yield 传入了什么,总的来说:
yield 本质就是占个位,写 yield 目的就是为了无需知道传入的 block 是做什么,如果要理解 m2 的 yield 传入什么才能读懂整个代码,那说明这里不应该用 block/yield 去实现这种需求,写成这样是你的代码设计有问题。
但是,ES6 新增了 Promise 和 Generator 已经解决了这些问题,把所有的异步都给我串起来!!!让你们看看什么才叫真正的优雅:
如果你认真学习过 Ruby,用 block 做 callback 使用也可以写出很优雅的代码,否则就算用 promise 或者 coroutine 也能写出不容易理解的代码,而且你举的代码例子无论从命名和实际用途都不清,如何评价是否优雅?show me the REAL code
(最后,个人认为 coroutine 最优雅)
http://threeifbywhiskey.github.io/2014/03/05/non-alphanumeric-ruby-for-fun-and-not-much-else/
_=$$/$$;__=_-_;@_=_+_;$_=@_+_;$__=@_+$_;$-_=$__*$_;@__=''<<$-_*($__+$_)+@_;$___=''<<$-_*$__-$__<<$-_*($__+@_)<<@__<<@__;@___=''<<$-_*$__-$_*$_<<$-_*($__+$_)-$_<<@__<<@__;(___=->{$.+=_;$><<($.%$-_==__ ?$___+@___:$.%$_==__ ?$___:$.%$__==__ ?@___:$.)<<(''<<$__*@_);$.<($__*@_)**@_?___[]:_})[]
mysql index 自动选择的问题,常见的坑,可以在查询里面加 FORCE INDEX 来解决
对于这种需求,我推荐 Decorator 模式,有现成的 gem draper 可以用
比如要加一个 FooBar 的逻辑,你的做法是在 config/initializer/business.rb 加一行:
Fanli.on(:create_user, [
SendWelcomeEmail,
GiveCouponIfXmas,
GiveInitialCash,
FooBar,
])
而我的做法是在 CreateUser 里面加一行
[SendWelcomeEmail, GiveCouponIfXmas, GiveInitialCash, FooBar].each
剩下其他代码都是一样的,你可以说你那个是配置,我那个需要修改代码,但是在这个例子里面看不出两者有什么本质区别。
如果非要改成配置的方式,那么我们改一下代码:
class CreateUser
def perform(args)
user = User.create!(args)
callbacks(args)
end
def callbacks(args)
callbacks_from_config.each do |clazz|
clazz.(args)
end
end
end
即使抽象一个 Base 出来,看起来和你的例子一模一样了,但是本质上还是意大利面条:
class Base
def perform(args)
_perform(args)
callbacks(args)
end
end
class CreateUser < Base
def _perform(args)
user = User.create!(args)
end
end
所以从这个例子上我看不出有用 Pub/Sub 的任何优势
代码结构和 README 里面的例子是一模一样的,例子怎么做单元测试,上面的代码也是一样做,单一职责并没有违反,做的事情都在各自代码里面,和例子也是一模一样的
感觉这和直接写意大利面代码没什么区别
class CreateUser
def perform(args)
user = User.create!(args)
[SendWelcomeEmail, GiveCouponIfXmas, GiveInitialCash].each do |clazz|
clazz.(args)
end
end
end
class SendWelcomeEmail
def self.call(args)
end
end
class GiveCouponIfXmas
def self.call(args)
end
end
class GiveInitialCash
def self.call(args)
end
end
&后面跟的是 Symbol,我们可以给它加个 monkey patch
class Symbol
def call(*args, &block)
->(caller, *rest) { caller.send(self, *rest, *args, &block) }
end
end
然后 call 在 Ruby 里面有.() 的便捷调用,就可以这样写了:
a = [{aa: '123'}, {aa: '321'}]
a.map &:[].(:aa)
忘记在哪里看到这个技巧的,但是真的很好用
[%w(hello world), %w(ruby on rails), %w(foo bar)].map(&:inject.(&:+))
nginx 设置一下,其他域名访问重定向到 ruby-china.org,就可以了,管局只看在浏览器里面输入域名,然后看返回的是什么
在 Java 里面很流行的做法,用 annotation 做 AOP,ruby 有一些 gem 可以让你很方便写,比如 https://github.com/comparaonline/co_aspects
你需要自己写一个 Aspect:
module CoAspects
module Aspects
class CacheAspect < Aspector::Base
around method_arg: true do |method, proxy, *args, &block|
cache_key = [self.class, method].join('.') + ':' + args.join(',')
Cache.fetch cache_key do
proxy.call(*args, &block)
end
end
end
end
end
用到这个 Aspect 的地方,写一个 annotation(伪)就可以了:
class Foo
aspects_annotations!
_cache
def bar
'bar'
end
end
数据库开 slow query log,5.7 还是慢可能和查询语句有关,把 log 到的语句 explain 一下看看
以前项目中用 imagemagick 执行命令行实现:
convert your.jpg -colors 256 -format %c -depth 8 histogram:info:-
mysql 有 select into,和 copy 命令类似,能支持各种选项,导出 csv 的例子:
SELECT * INTO OUTFILE '/tmp/result.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM table;
用超过上限的数字来表示 NaN,保证 dump 回来的数据能正常显示 NaN?哈哈哈哈
https://github.com/ohler55/oj/blob/cecfe196af51e8fc964cd6d9751e50724f1cb8bf/ext/oj/oj.h#L73
#define INF_VAL "3.0e14159265358979323846"
#define NINF_VAL "-3.0e14159265358979323846"
#define NAN_VAL "3.3e14159265358979323846"
这个 eval 解决 Leetcode 问题的想法好有趣
#15 楼 @tianlitao end_a < start_c 就是||表达式右边的第二种情况呀
我一般 CRUD 不写测试代码,只写测试代码测试复杂逻辑和用来重现用户报告的 Bug 然后并修复它
判断时间区段重叠可以通过这样的方式来简化:
先是判断时间区段不重叠,有 2 种情况
|start_a ----- end_a|
|start_b ----- end_b|
---------------------------------------------
|start_a ----- end_a|
|start_b ----- end_b|
得出不重叠的表达式是:
start_a > end_b || end_a < start_b
那么不重叠就是取反
!(start_a > end_b || end_a < start_b)
布尔运算等价于
start_a <= end_b and end_a >= start_b
代码可以简化成:
plan = Plan.where('start_time <= ? and end_time >= ?', end_at, start_at)
是的,Ruby 没有 primitive 类型,proc 也是 Object,method 也是 Object
1.is_a? Object
#true
proc = -> {puts 1}
proc.is_a? Object
#true
class String
def -(s)
self.gsub(s, '')
end
end
"abc".method(:-).is_a? Object
#true
@bastengao @lainuo ruby 用的 OpenSSL 可以直接设置 padding,没有必要自己再去实现一次
cipher.padding = 7
看了一下 rfc,是要求有空格的,那就不是 bug 了,是发起方没有遵循 rfc http://www.rfc-base.org/txt/rfc-2183.txt
disposition := "Content-Disposition" ":"
disposition-type
*(";" disposition-parm)
恭喜你找到了 rack 的 bug,这里的正则表达式用了\s: \sfilename,可以去提个 pull request 了