| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
| |
Before this commit `Module#redefine_method` always changes
visibility of redefined method to `public`.
This commit changes behavior of Module#redefine_method` to
keep method visibility.
|
|
|
|
|
| |
In later code examples, it is better to write how `Module#anonymous?`
works.
|
| |
|
|
|
|
|
| |
This is primarily to fix method redefinition warnings in class_attribute
but may be of use in other places where we define singleton methods.
|
|\
| |
| |
| | |
Handle invalid UTF-8 strings when HTML escaping
|
| |
| |
| |
| |
| |
| |
| | |
Use `ActiveSupport::Multibyte::Unicode.tidy_bytes` to handle invalid UTF-8
strings in `ERB::Util.unwrapped_html_escape` and `ERB::Util.html_escape_once`.
Prevents user-entered input passed from a querystring into a form field from
causing invalid byte sequence errors.
|
|\ \
| | |
| | | |
Use Module.prepend instead of alias_method and unify behavior of all Numeric extensions
|
| | |
| | |
| | |
| | | |
alias_method
|
|\ \ \
| | | |
| | | | |
ActiveSupport: Fixing issue when delegating to methods named "block", "args", or "arg"
|
| | | | |
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
The default timestamp used for AR is `updated_at` in nanoseconds! (:nsec) This causes issues on any machine that runs an OS that supports nanoseconds timestamps, i.e. not-OS X, where the cache_key of the record persisted in the database (milliseconds precision) is out-of-sync with the cache_key in the ruby VM.
This commit adds:
A test that shows the issue, it can be found in the separate file `cache_key_test.rb`, because
- model couldn't be defined inline
- transactional testing needed to be turned off to get it to pass the MySQL tests
This seemed cleaner than putting it in an existing testcase file.
It adds :usec as a dateformat that calculates datetime in microseconds
It sets precision of cache_key to :usec instead of :nsec, as no db supports nsec precision on timestamps
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
`each_with_object` allocates an array for each kv pair. Switching to
the slightly more verbose but less allocatey `each_pair` eliminates
array allocations. Eliminating this allocation returns AR objects to
have constant array allocations regardless of the number of columns the
object has.
Here is test code:
```ruby
require 'active_record'
class Topic < ActiveRecord::Base
end
20.times do |i|
Process.waitpid fork {
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
ActiveRecord::Base.connection.instance_eval do
create_table(:topics) do |t|
t.string :title, limit: 250
t.string :author_name
t.string :author_email_address
t.string :parent_title
t.string :type
t.string :group
i.times do |j|
t.string :"aaa#{j}"
end
t.timestamps null: true
end
end
ObjectSpace::AllocationTracer.setup(%i{type})
Topic.create title: "aaron" # heat cache
result = ObjectSpace::AllocationTracer.trace do
10.times do |i|
Topic.create title: "aaron #{i}"
end
end
puts "#{Topic.columns.length},#{(result.find { |k,v| k.first == :T_ARRAY }.last.first / 10)}"
}
end
```
Before this commit:
```
9,166
10,167
11,168
12,169
13,170
14,171
15,172
16,173
17,174
18,175
19,176
20,177
21,178
22,179
23,180
24,181
25,182
26,183
27,184
28,185
```
After:
```
9,157
10,157
11,157
12,157
13,157
14,157
15,157
16,157
17,157
18,157
19,157
20,157
21,157
22,157
23,157
24,157
25,157
26,157
27,157
28,157
```
Left side is the number of columns, right is the number of allocations
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
deep_dup'ing a hash will dup the keys as well as the values. Since
string keys from the source hash will be frozen, and the dup'd objects
are immediately dup'd and frozen on insert in to the hash, the end user
will only ever see two frozen strings. Since the strings are immutable,
this commit just cheats a little and reuses the immutable strings.
Just to reiterate, before this commit, deep duping a hash that looks
like this: `{ "foo" => "bar" }` will generate two new instances of
"foo". One is created when `deep_dup` is called on "foo", and the other
is created when the newly allocated "foo" string is inserted in to the
hash. The user never sees the intermediate "foo", and both copies of
"foo" that the user *can* access will be frozen, so in this case we just
reuse the existing frozen key.
The upshot is that after this change, string allocations on AR
allocations become constant regardless of the number of columns the
model has.
```ruby
require 'active_record'
class Topic < ActiveRecord::Base
end
20.times do |i|
Process.waitpid fork {
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
ActiveRecord::Base.connection.instance_eval do
create_table(:topics) do |t|
t.string :title, limit: 250
t.string :author_name
t.string :author_email_address
t.string :parent_title
t.string :type
t.string :group
i.times do |j|
t.integer :"aaa#{j}"
end
t.timestamps null: true
end
end
ObjectSpace::AllocationTracer.setup(%i{type})
Topic.create title: "aaron" # heat cache
result = ObjectSpace::AllocationTracer.trace do
10.times do |i|
Topic.create title: "aaron #{i}"
end
end
puts "#{Topic.columns.length},#{(result.find { |k,v| k.first == :T_STRING }.last.first / 10)}"
}
end
```
If you run the above script before this commit, the output looks like
this:
```
[aaron@TC rails (master)]$ be ruby -rallocation_tracer test.rb
9,105
10,107
11,109
12,111
13,113
14,115
15,117
16,119
17,121
18,123
19,125
20,127
21,129
22,131
23,133
24,135
25,137
26,139
27,141
28,143
```
The left column is the number of methods, the right column is the number
of string allocations.
Running against this commit, the output is:
```
[aaron@TC rails (master)]$ be ruby -rallocation_tracer test.rb
9,87
10,87
11,87
12,87
13,87
14,87
15,87
16,87
17,87
18,87
19,87
20,87
21,87
22,87
23,87
24,87
25,87
26,87
27,87
28,87
```
As you can see, there is now only a constant number of strings
allocated, regardless of the number of columns the model has.
|
|\ \ \ \
| | | | |
| | | | | |
[ci skip] Fix #seconds_since_midnight documentation output it will al…
|
| | | | |
| | | | |
| | | | |
| | | | | |
return floating pointnumber
|
|\ \ \ \ \
| | | | | |
| | | | | | |
Fix Time.now format in documentation [ci skip]
|
| |/ / / / |
|
|\ \ \ \ \
| | | | | |
| | | | | | |
Use #current instead of #now to prevent zone issues and use new ruby …
|
| |/ / / /
| | | | |
| | | | |
| | | | | |
application's time zone
|
|\ \ \ \ \
| |/ / / /
|/| | | | |
|
| | | | | |
|
| | | | | |
|
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
Change ^ and $ operators to \A and \z to prevent
code injection after the line breaks
|
| | | | | |
|
|\ \ \ \ \
| | | | | |
| | | | | | |
Update docs for `formatted_offset`
|
| | | | | |
| | | | | |
| | | | | | |
Output of `formatted_offset` is depends on input so it’s not always in +HH:MM format. Possible outputs are “+5:30”, “+530” or provided alternate UTC string [ci skip]
|
|\ \ \ \ \ \
| | | | | | |
| | | | | | | |
Updated docs for transform_keys & transform_values
|
| | | | | | | |
|
| |/ / / / / |
|
|/ / / / /
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
We're calling this function on an empty hash as part of copying the
attribute set during dirty checking initialization. The new structure
caused a performance regression on loading records from the database.
This causes `User.all.to_a` to perform about 10% faster w/ 10k records.
Calculating -------------------------------------
User.all - master 9.000 i/100ms
User.all - sg-fix-ar-regression
8.000 i/100ms
-------------------------------------------------
User.all - master 81.236 (± 7.4%) i/s - 405.000
User.all - sg-fix-ar-regression
89.716 (± 7.8%) i/s - 448.000
|
| | | | | |
|
|\ \ \ \ \
| | | | | |
| | | | | | |
Added Examples in docs for internal behavior of Array#to_formatted_s [ci skip]
|
| | | | | | |
|
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
The concept of a blank date or time doesn't make sense so we can short
circuit the calls for `blank?` on these classes to gain small speed boost.
Fixes #21657
|
| | | | | | |
|
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Call to Object#try was removed with this pull request https://github.com/rails/rails/pull/21596
|
|\ \ \ \ \ \
| | | | | | |
| | | | | | | |
Correcting `NameError` error message in `mattr_reader` method. [ci skip]
|
| |/ / / / /
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
commit https://github.com/rails/rails/commit/7dfbd91b0780fbd6a1dd9bfbc176e10894871d2d, `NameError` includes attribute_name also in error message [ci skip]
|
| | | | | | |
|
|/ / / / /
| | | | |
| | | | |
| | | | | |
@rafaelfranca suggested in https://github.com/rails/rails/commit/f7c7bcd9c2a8b0e8c2840295d001d2d4dfd4cfae that code examples should display
the result after `# =>` and not after `#=>`.
|
|\ \ \ \ \
| |/ / / /
|/| | | | |
Corrected `to_time` output in ActiveSupport Date Conversion docs [ci …
|
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
https://github.com/rails/rails/commit/48583f8bf74d1cefefea3cd6591bd546a9eaff6c, to_time returns times formatted as YYYY-MM-DD HH:MM:SS UTC [ci skip]
`to_time` method now returns in `YYYY-MM-DD HH:MM:SS UTC` format.
|
|\ \ \ \ \ |
|
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
[ci skip]
|
| |/ / / /
|/| | | | |
|
| | | | |
| | | | |
| | | | | |
This was happened after this commit https://github.com/rails/rails/commit/2ebf47aea21ff8ac10681e53e78dd7a0e5c31c6e
|
| | | | |
| | | | |
| | | | | |
`DateTime.utc` is not a valid method. It gives `NoMethodError: undefined method `utc` for DateTime:Class`. As we know that we can calculate `utc` time from `Time` Class, but we can’t calculate `utc` time from `DateTime` Class.
|
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
Saves about 6 MB, about 40% faster.
**strip_heredoc.rb**
```ruby
require "active_support/core_ext/object/try"
require "get_process_mem"
class String
def strip_heredoc
indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
gsub(/^[ \t]{#{indent}}/, '')
end
end
if ENV["MEASURE_MEMORY"] == "yes"
mem = GetProcessMem.new
GC.start
GC.disable
10000.times do
<<-MSG.strip_heredoc
xhr and xml_http_request methods are deprecated in favor of
`get :index, xhr: true` and `post :create, xhr: true`
MSG
end
before = mem.mb
after = mem.mb
GC.enable
puts "Before: #{before} MiB"
puts "After: #{after} MiB"
puts "Diff: #{after - before} MiB"
end
```
**patched_strip_heredoc.rb**
```ruby
require "active_support/core_ext/object/try"
require "get_process_mem"
class String
def patched_strip_heredoc
gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "".freeze)
end
end
if ENV["MEASURE_MEMORY"] == "yes"
mem = GetProcessMem.new
GC.start
GC.disable
10000.times do
<<-MSG.patched_strip_heredoc
xhr and xml_http_request methods are deprecated in favor of
`get :index, xhr: true` and `post :create, xhr: true`
MSG
end
before = mem.mb
after = mem.mb
GC.enable
puts "Before: #{before} MiB"
puts "After: #{after} MiB"
puts "Diff: #{after - before} MiB"
end
```
**Before**
```
$ MEASURE_MEMORY=yes ruby strip_heredoc.rb
Before: 44.73828125 MiB
After: 44.7734375 MiB
Diff: 0.03515625 MiB
```
**After**
```
$ MEASURE_MEMORY=yes ruby patched_strip_heredoc.rb
Before: 37.9765625 MiB
After: 38.015625 MiB
Diff: 0.0390625 MiB
```
`44.7734375 - 38.015625 = 6.75`
=> **Saves about 6.75 MiB**
**benchmark.rb**
```ruby
require "benchmark/ips"
require_relative "./strip_heredoc"
require_relative "./patched_strip_heredoc"
def original
<<-MSG.strip_heredoc
xhr and xml_http_request methods are deprecated in favor of
`get :index, xhr: true` and `post :create, xhr: true`
MSG
end
def patched
<<-MSG.patched_strip_heredoc
xhr and xml_http_request methods are deprecated in favor of
`get :index, xhr: true` and `post :create, xhr: true`
MSG
end
Benchmark.ips do |x|
x.report("original") { original }
x.report(" patched") { patched }
x.compare!
end
```
```
$ ruby -v benchmark.rb
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]
Calculating -------------------------------------
original 5.652k i/100ms
patched 6.477k i/100ms
-------------------------------------------------
original 54.076k (± 5.7%) i/s - 271.296k
patched 74.557k (± 6.2%) i/s - 375.666k
Comparison:
patched: 74557.0 i/s
original: 54076.4 i/s - 1.38x slower
```
=> **About 38% faster**
1. Clone rails project `git clone git@github.com:rails/rails.git`
2. Apply this patch to
`activesupport/lib/active_support/core_ext/string/strip.rb`
3. `cd activesupport`
4. run `rake`
5. And tests passed:
```
➜ activesupport $ rake
/Users/Juan/.rubies/ruby-2.2.2/bin/ruby -w -I"lib:test"
"/Users/Juan/.rubies/ruby-2.2.2/lib/ruby/2.2.0/rake/rake_test_loader.rb"
"test/**/*_test.rb"
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
........................................................................
......................................................................S.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Finished in 15.343004s, 214.2344 runs/s, 24902.4898 assertions/s.
3287 runs, 382079 assertions, 0 failures, 0 errors, 48 skips
You have skipped tests. Run with --verbose for details.
```
|
| | | | | |
|
| | | | | |
|