Is there a reason we're only taking this short cut for frozen strings and not other immutable objects commonly used as hash keys (eg. symbols and integers)?
initial tests suggest a ~30% performance improvement...
```
require 'benchmark'
class Object
def deep_dup
dup
end
alias deep_dup_all deep_dup
end
class Hash
def deep_dup
hash = dup
each_pair do |key, value|
if key.frozen? && ::String === key
hash[key] = value.deep_dup
else
hash.delete(key)
hash[key.deep_dup] = value.deep_dup
end
end
hash
end
def deep_dup_all
hash = dup
each_pair do |key, value|
if key.frozen?
hash[key] = value.deep_dup_all
else
hash.delete(key)
hash[key.deep_dup_all] = value.deep_dup_all
end
end
hash
end
end
data = Hash[('aaa'..'zzz').map {|k| [k.to_sym, k]}]
control = Benchmark.realtime do
30.times { data.deep_dup }
end
experiment = Benchmark.realtime do
30.times { data.deep_dup_all }
end
puts "%.3f v %.3f => %d%% speed up" % [ control, experiment, (control - experiment) / control * 100 ]
```
In redis cache store, options to `fetch_multi` are passed correctly to
`write_multi` but not to `read_multi`. This causes cache always to be missed
when passing `namespace` option to it.
- Disables Dalli compression in MemCacheStore.
- Fixes issue where redundant compression in Dalli can cause values to
either be compressed twice, or compressed when they fall below the
specified compression threshold.
- Fixes issue where reads with raw: true using redis or memcached cache
store, will compress values on reads.
- Should speed up raw cache reads by preventing unnecessary cpu intensive
operation.
### Summary
This PR fixes `NoMethodError` for `ActiveSupport::Cache::FileStore.cleanup` when using [Sprockets](https://github.com/rails/sprockets).
`FileStore.cleanup` assumes entry object is a `Cache::Entry`.
An entry obejct is returned from `FileStore.read_entry` method.
If `FileStore.read_entry` returns object that cannot respond to `expired?` method, `FileStore.cleanup` will fail.
Sprockets generates cache file in tmp/cache/assets.
If `FileStore.read_entry` gets these Sprocket's cache file, this method creates entry object which cannot respond to `expired?` method.
In my project, this error occured and failed to execute `ActiveSupport::Cache::FileStore.cleanup`.
This PR adds a `is_a?` checking to entry object in `read_entry` method.
This is most easiest done by switching to before_setup, which fits since
we're also testing the ordering of the reset calls provided by the
TestHelper.
Currently there's a problem with ActiveSupport::CurrentAttributes where
they don't reset unless there's a controller or a job executing.
This is because we correctly hook into the controller/job executor to
reset them.
However, we were missing plain tests, so this is that.
cd31e113c0663dabcdc293d9e7dc3b6e1392db5d switched to passing options as
keyword arguments, which always creates a new hash.
9e4ff29f748b05c3a949f0d75167950039b6cda8 removed a now-unnecessary call
to `dup`, since the options could no longer be accidentally mutated.
a55620f3fa89d957817349e5170f686d505eeee4 switched back to passing
options as a positional argument for Ruby < 2.7, but didn't restore the
call to `dup`, which meant that the same options hash was now passed
with every method call and mutations leaked from one call to another.
* master-sec:
Check that request is same-origin prior to including CSRF token in XHRs
HMAC raw CSRF token before masking it, so it cannot be used to reconstruct a per-form token
activesupport: Avoid Marshal.load on raw cache value in RedisCacheStore
activesupport: Avoid Marshal.load on raw cache value in MemCacheStore
Return self when calling #each, #each_pair, and #each_value instead of the raw @parameters hash
Include Content-Length in signature for ActiveStorage direct upload
Empty backtraces means you didn't run any code, which isn't the case,
and goes against the contract that Minitest.backtrace_cleaner expects.
This fixes a bug I've seen in a number of reports.
It would be nice if this got backported to whatever versions are
active, as this keeps coming back on minitest issues.
The same value for the `raw` option should be provided for both reading and
writing to avoid Marshal.load being called on untrusted data.
[CVE-2020-8165]
Dalli is already being used for marshalling, so we should also rely
on it for unmarshalling. Since Dalli tags the cache value as marshalled
it can avoid unmarshalling a raw string which might have come from
an untrusted source.
[CVE-2020-8165]
On constant missing Ruby call `#inspect` on the receiver to build
the error message.
For instance, the error message for `Foo::Bar` will be `"#{Foo.inspect}::Bar"`.
And since Active Record override the model classes inspect method, this
breaks `missing_name` assumptions.
Until now it worked because missing_name was only called on errors
raised by the classic autoloader, and the classic autoloader calls
`#name` to build its error message.
In the past, we sometimes hit missing `Symbol#start_with?` and
`Symbol#end_with?`.
63256bc5d7a8e812964d
So I proposed `Symbol#start_with?` and `Symbol#end_with?` to allow duck
typing that methods for String and Symbol, then now it is available in
Ruby 2.7.
https://bugs.ruby-lang.org/issues/16348
Using `String#starts_with?` and `String#ends_with?` could not be gained
that conveniency, so it is preferable to not use these in the future.
I wrote this shell script to find words from the Rails repo,
so I can paste them into https://www.horsepaste.com/ for
the [codenames game](https://en.m.wikipedia.org/wiki/Codenames_(board_game)).
```bash
git grep -Il '' | \
grep -v -E "CHANGELOG|Gemfile|gemspec|package\.json|yarn\.lock" | \
xargs cat | \
sed '/[^ ]\{10,\}/d' | \
sed 's/\([A-Z]\)/ \1/g' | \
tr 'A-Z' 'a-z' | \
tr -c -s 'a-z' '\n' | \
sed '/^.\{0,3\}$/d' | \
sort | \
uniq | \
tr '\n' ',' | \
pbcopy
```
You can see the result in https://www.horsepaste.com/rails-fixed.
Click "Next game" to cycle the words.
Found some typos in the codebase from this 😂
This is how I generated the list of possible typos:
```bash
git grep -Il '' | \
grep -v -E "CHANGELOG|Gemfile|gemspec|package\.json|yarn\.lock" | \
xargs cat | \
sed '/[^ ]\{10,\}/d' | \
sed 's/\([A-Z]\)/ \1/g' | \
tr 'A-Z' 'a-z' | \
tr -c -s 'a-z' '\n' | \
sed '/^.\{0,3\}$/d' | \
sort | \
uniq | \
aspell --ignore-case list
```
I manually reviewed the list and made the corrections
in this commit. The rest on the list are either:
* Bugs in my script: it split things like "doesn't" into
"doesn" and "t", if find things like `#ffffff` and
extracts "ffffff" as a word, etc
* British spelling: honour, optimised
* Foreign words: bonjour, espanol
* Names: nginx, hanekawa
* Technical words: mutex, xhtml
* Portmanteau words: autosave, nodelist
* Invented words: camelize, coachee
* Shortened words: attrs, repo
* Deliberate typos: hllo, hillo (used in code examples, etc)
* Lorem ipsum words: arcu, euismod
This is the [output](https://gist.github.com/chancancode/eb0b573d667dc31906f33f1fb0b22313)
of the script *after* fixing the typos included in this
commit. In theory, someone can run that command again in
the future and compare the output to catch new typos (i.e.
using my list to filter out known typos).
Limitations: the aspell dictionary could be wrong, I
could have miss things, and my script ignores words that
are less than 3 characters or longer than 10 characters.
Calling `#tagged` without a block now returns a new logger with the tags
applied. This is useful for when you want to tag an individual log line,
rather than an entire request.
`(1..10).cover?(5..3)` now returns `false`, as it does in plain Ruby. Previously this returned `true`.
Also update `#include?` and `#===` behavior to match.
Add Date and Time `#yesterday?` and `#tomorrow?` alongside `#today?`.
Aliased to `#prev_day?` and `#next_day?` to match the existing `#prev/next_day` methods.
This allows `pick` to be called on an object that could either be an
enumerable or a relation.
Also clarify the documentation for `Enumerable#pluck`, and add an
example of plucking multiple keys to the core extensions guide.
- The `halted_callback_hook` method is called whenever the
`terminator` halt the callback execution.
Usually, this translate to when a `before` callback throw
an `:abort`.
<details>
<summary> Example </summary>
```ruby
class Foo
include ActiveSupport::Callbacks
define_callbacks :save
set_callback(:save, :before) { throw(:abort) }
def run
run_callbacks(:save) do
'hello'
end
end
def halted_callback_hook(filter)
# filter is the proc passed to `set_callback` above
end
end
```
</details>
### Problem
When a class has multiple callbacks, (i.e. `save`, `validate` ...),
it's impossible to tell in the halted_callback_hook which type of
callback halted the execution.
This is useful to take different action based on the callback.
<details>
<summary> Use Case </summary>
```ruby
class Foo
include ActiveSupport::Callbacks
define_callbacks :save
define_callbacks :validate
set_callback(:save, :before) { throw(:abort) }
set_callback(:validate, :before) { throw(:abort) }
def run
run_callbacks(:validate) do
...
end
run_callbacks(:save) do
...
end
end
def halted_callback_hook(filter)
Rails.logger.warn("Couldn't save the record, the ??? callback halted the execution")
end
end
```
</details>
### Solution
Allow `halted_callback_hook` to receive a second argument which is
the name of the callback being run.