| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
| | |
|
| |
| |
| |
| |
| |
| | |
We can save a few objects by freezing the `replacement` string. We save a few more by down-casing the string in memory instead of allocating a new one. We save far more objects by checking for the default separator `"-"`, and using pre-generated regular expressions.
We will save 209,231 bytes and 1,322 objects.
|
|/
|
|
|
|
| |
In `apply_inflections` a string is down cased and some whitespace stripped in the front (which allocate strings). This would normally be fine, however `uncountables` is a fairly small array (10 elements out of the box) and this method gets called a TON. Instead we can keep an array of valid regexes for each uncountable so we don't have to allocate new strings.
This change buys us 325,106 bytes of memory and 3,251 fewer objects per request.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I wrote a utility that helps find areas where you could optimize your program using a frozen string instead of a string literal, it's called [let_it_go](https://github.com/schneems/let_it_go). After going through the output and adding `.freeze` I was able to eliminate the creation of 1,114 string objects on EVERY request to [codetriage](codetriage.com). How does this impact execution?
To look at memory:
```ruby
require 'get_process_mem'
mem = GetProcessMem.new
GC.start
GC.disable
1_114.times { " " }
before = mem.mb
after = mem.mb
GC.enable
puts "Diff: #{after - before} mb"
```
Creating 1,114 string objects results in `Diff: 0.03125 mb` of RAM allocated on every request. Or 1mb every 32 requests.
To look at raw speed:
```ruby
require 'benchmark/ips'
number_of_objects_reduced = 1_114
Benchmark.ips do |x|
x.report("freeze") { number_of_objects_reduced.times { " ".freeze } }
x.report("no-freeze") { number_of_objects_reduced.times { " " } }
end
```
We get the results
```
Calculating -------------------------------------
freeze 1.428k i/100ms
no-freeze 609.000 i/100ms
-------------------------------------------------
freeze 14.363k (± 8.5%) i/s - 71.400k
no-freeze 6.084k (± 8.1%) i/s - 30.450k
```
Now we can do some maths:
```ruby
ips = 6_226k # iterations / 1 second
call_time_before = 1.0 / ips # seconds per iteration
ips = 15_254 # iterations / 1 second
call_time_after = 1.0 / ips # seconds per iteration
diff = call_time_before - call_time_after
number_of_objects_reduced * diff * 100
# => 0.4530373333993266 miliseconds saved per request
```
So we're shaving off 1 second of execution time for every 220 requests.
Is this going to be an insane speed boost to any Rails app: nope. Should we merge it: yep.
p.s. If you know of a method call that doesn't modify a string input such as [String#gsub](https://github.com/schneems/let_it_go/blob/b0e2da69f0cca87ab581022baa43291cdf48638c/lib/let_it_go/core_ext/string.rb#L37) please [give me a pull request to the appropriate file](https://github.com/schneems/let_it_go/blob/b0e2da69f0cca87ab581022baa43291cdf48638c/lib/let_it_go/core_ext/string.rb#L37), or open an issue in LetItGo so we can track and freeze more strings.
Keep those strings Frozen
![](https://www.dropbox.com/s/z4dj9fdsv213r4v/let-it-go.gif?dl=1)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
```ruby
require 'benchmark/ips'
Benchmark.ips do |x|
x.report("$&") {
"foo".sub(/f/) { $&.upcase }
}
x.report("block var") {
"foo".sub(/f/) {|match| match.upcase }
}
end
```
```
Calculating -------------------------------------
$& 48.658k i/100ms
block var 49.666k i/100ms
-------------------------------------------------
$& 873.156k (± 9.3%) i/s - 4.331M
block var 969.744k (± 9.2%) i/s - 4.818M
```
It's faster, and gets rid of a few "magic" global variables
|
|
|
|
|
|
|
|
| |
Fix the guide to state that Rails uses Minitest as the default test
framework.
Remove unnecessary mention to Test::Unit from the API docs
('constantize' and 'safe_constantize').
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
https://github.com/ruby/ruby/pull/579 - there is a new optimization
since ruby 2.2
Previously regexp patterns were faster (since a string was converted to
regexp underneath anyway). But now string patterns are faster and
better reflect the purpose.
Benchmark.ips do |bm|
bm.report('regexp') { 'this is ::a random string'.gsub(/::/, '/') }
bm.report('string') { 'this is ::a random string'.gsub('::', '/') }
bm.compare!
end
# string: 753724.4 i/s
# regexp: 501443.1 i/s - 1.50x slower
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Many methods in ActiveSupport::Inflector were actually documenting
the String methods with the same name.
For instance the doc for `camelize` said:
> If the argument to +camelize+ is set to <tt>:lower</tt>...
while it should say:
> If the +uppercase_first_letter+ parameter is set to false
[ci skip]
|
| |
|
| |
|
| |
|
| |
|
|\
| |
| |
| | |
Fix underscore inflector handling of namespaced and adjacent acronyms
|
|/
|
|
|
|
|
|
|
|
|
|
|
| |
I suspect that positive lookbehind would have been used in the
original implementation had it been available in supported Ruby
versions at the time. Now that Rails requires Ruby 1.9.2 or above,
this is no longer an issue.
This fixes #14146 for acronyms such as APIRESTful. This technique also
addresses namespaced acronyms that are not entirely uppercased. This
was broken when the commit was originally written but has since been
fixed in ccbb481. The latter does not deal with adjacent acronyms so
this commit wins.
|
|
|
|
|
|
| |
Fixes #8015, #9756.
[Fred Wu & Matthew Draper]
|
|\
| |
| | |
Avoid relying on error messages when rescuing
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
When we are rescuing from an error, it's a brittle approach to do checks
with regular expressions on the raised message because it may change in
in the future and error messages are different across implementations.
The NameError API could be improved at the MRI level but for now we need
to rely on its #name. A #== check will only pass for top level constants
or only when the last constant of the path is missing so we need to rely
on #include? instead. For instance:
begin
Namespace::Foo
rescue NameError => e
e.name # => :Namespace
end
However, if the name-space already exists, only the name of the first
missing constant in the path is returned (e.g. for Math::PHI, the name
would be :PHI). JRuby will return a fully qualified name (:"Math::PHI").
We need to keep the == check for 1.9 compatibility since const_get will
raise a NameError with a name attribute set to the given string if it's
one of "::" or "".
See http://git.io/jnSN7g for further information.
|
|/
|
|
|
|
| |
Originally introduced in f9086d63, the documentation of this method is
wrong as #const_regexp returns a string to easy the interpolation inside
regular expressions.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Since d3071db1, the apply_inflections method check if the downcased
version of a string is contained inside the "whitelist" of uncountable
words. However, if the word is composed of capital letters, it won't be
matched in the list while it should.
We can't simply revert to the previous behavior as there is a
performance concern (benchmarked over /usr/share/dict/words):
Before d3071db1 135.610000 0.290000 135.900000 (137.807081)
Since d3071db1 22.170000 0.020000 22.190000 ( 22.530005)
With the patch 22.060000 0.020000 22.080000 ( 22.125771)
Benchmarked with http://git.io/aFnWig
This way, the solution is to put the down-case version of words inside
the @uncountables array.
|
|
|
|
|
|
|
|
|
|
| |
* Strips leading underscores.
* Changes some unnecessary gsub!s to sub!s.
* Replaces some anchors ^, $ with \A, \z.
* Documents that human inflection rules are applied.
* Documents that words are downcased except acronyms.
* Adds an example with an acronym.
* Rewords docs.
|
|\
| |
| | |
Correct comment [ci skip]
|
| | |
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
After this 21dbe6f39b57f52967e92716dbd5e2b894e7a64c
2.1.1 :001 > 'business'.classify
=> "Business"
2.1.1 :004 > 'calculus'.classify
=> "Calculu"
2.1.1 :005 >
|
|/ |
|
| |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Benchmark:
Benchmark.ips do |x|
x.report("home") { "home".underscore }
x.report("Home") { "Home".underscore }
x.report("homeBase") { "homeBase".underscore }
x.report("home::base") { "home::base".underscore }
end
Before:
Calculating -------------------------------------
home 2598 i/100ms
Home 2463 i/100ms
homeBase 2300 i/100ms
home::base 2086 i/100ms
-------------------------------------------------
home 28522.3 (±14.7%) i/s - 140292 in 5.065102s
Home 29165.8 (±14.9%) i/s - 140391 in 5.000475s
homeBase 26218.5 (±7.1%) i/s - 131100 in 5.030485s
home::base 27712.3 (±5.9%) i/s - 139762 in 5.064077s
After:
Calculating -------------------------------------
home 23163 i/100ms
Home 2432 i/100ms
homeBase 2160 i/100ms
home::base 2265 i/100ms
-------------------------------------------------
home 1501614.8 (±10.2%) i/s - 7412160 in 5.009540s
Home 28754.0 (±8.5%) i/s - 143488 in 5.033886s
homeBase 25331.1 (±5.6%) i/s - 127440 in 5.047940s
home::base 27089.9 (±5.5%) i/s - 135900 in 5.033516s
|
| |
|
| |
|
|
|
|
|
|
|
|
|
| |
According to our guideline, we leave 1 space between `#` and `=>`, so we
want `# =>` instead of `#=>`.
Thanks to @fxn for the suggestion.
[ci skip]
|
|
|
|
|
|
|
| |
So strings can be humanized without being capitalized:
'employee_salary'.humanize # => "Employee salary"
'employee_salary'.humanize(capitalize: false) # => "employee salary"
|
| |
|
|
|
|
|
|
|
| |
Benchmark:
user system total real
old 6.090000 0.120000 6.210000 ( 6.202039)
new 5.930000 0.110000 6.040000 ( 6.042022)
|
|
|
|
|
|
|
| |
Benchmark:
user system total real
old 5.960000 0.020000 5.980000 ( 5.981754)
new 5.740000 0.030000 5.770000 ( 5.757201)
|
|
|
|
|
|
|
| |
Benchmark:
user system total real
old 0.740000 0.000000 0.740000 ( 0.744358)
new 0.550000 0.000000 0.550000 ( 0.553690)
|
|\
| |
| | |
Remove unnecessary require from active_support/inflector/methods.rb
|
| |
| |
| |
| |
| |
| | |
`active_support/inflections` already requires
`active_support/inflector/inflections`. There's no need to require it in
`active_support/inflector/methods`.
|
| | |
|
| |
| |
| |
| | |
We need to return Regexp.escape(camel_cased_word)
if the split is blank.
|
|/ |
|
|
|
|
|
|
|
|
|
| |
This reverts commit 867dc1700f32aae6f98c4651bd501597e6b52bc0, reversing
changes made to 9a421aaa8285cf2a7ecb1af370748b0337818930.
This breaks anyone who's using ForceSSL: https://travis-ci.org/rails-api/rails-api/jobs/5556065
Please see comments on #8156 for some discussion.
|
|
|
|
| |
disregarding specified acronyms, fixes #8015
|
| |
|
| |
|
|\
| |
| | |
Inflector irregular singularize rules
|
| | |
|
|/ |
|