Sam Rawlins / @srawlins
$ rbenv install 2.1
$ rvm install ruby-2.1
= NEWS for Ruby 2.1.0
This document is a list of user visible feature changes made between
releases except for bug fixes.
Note that each entry is kept so brief that no reason behind or
reference information is supplied with. For a full list of changes
with all sufficient information, see the ChangeLog file.
== Changes since the 2.0.0 release
=== Language changes
* Now the default values of keyword arguments can be omitted. Those
"required keyword arguments" need giving explicitly at the call time.
* Added suffixes for integer and float literals: 'r', 'i', and 'ri'.
* "42r" and "3.14r" are evaluated as Rational(42, 1) and 3.14.rationalize,
respectively. But exponential form with 'r' suffix like "6.022e+23r" is
not accepted because it is misleading.
* "42i" and "3.14i" are evaluated as Complex(0, 42) and Complex(0, 3.14),
respectively.
* "42ri" and "3.14ri" are evaluated as Complex(0, 42r) and Complex(0, 3.14r),
respectively.
* def-expr now returns the symbol of its name instead of nil.
* Added 'f' suffix for string literals that returns a frozen String object.
=== Core classes updates (outstanding ones only)
* Binding
* New methods
* Binding#local_variable_get(symbol)
* Binding#local_variable_set(symbol, obj)
* Binding#local_variable_defined?(symbol)
* GC
* added environment variable:
* RUBY_HEAP_SLOTS_GROWTH_FACTOR: growth rate of the heap.
* Integer
* New methods
* Fixnum#bit_length
* Bignum#bit_length
* Bignum performance improvement
* Use GMP if available.
GMP is used only for several operations:
multiplication, division, radix conversion, GCD
* IO
* extended methods:
* IO#seek supports SEEK_DATA and SEEK_HOLE as whence.
* IO#seek accepts symbols (:CUR, :END, :SET, :DATA, :HOLE) for 2nd argument.
* IO#read_nonblock accepts optional `exception: false` to return symbols
* IO#write_nonblock accepts optional `exception: false` to return symbols
* Kernel
* New methods:
* Kernel#singleton_method
* Module
* New methods:
* Module#using, which activates refinements of the specified module only
in the current class or module definition.
* Module#singleton_class? returns true if the receiver is a singleton class
or false if it is an ordinary class or module.
* extended methods:
* Module#refine is no longer experimental.
* Module#include and Module#prepend are now public methods.
* Mutex
* misc
* Mutex#owned? is no longer experimental.
* Numeric
* extended methods:
* Numeric#step allows the limit argument to be omitted, in which
case an infinite sequence of numbers is generated. Keyword
arguments `to` and `by` are introduced for ease of use.
* Process
* New methods:
* alternative methods to $0/$0=:
* Process.argv0() returns the original value of $0.
* Process.setproctitle() sets the process title without affecting $0.
* Process.clock_gettime
* Process.clock_getres
* RbConfig
* New constants:
* RbConfig::SIZEOF is added to provide the size of C types.
* String
* New methods:
* String#scrub and String#scrub! verify and fix invalid byte sequence.
* extended methods:
* If invalid: :replace is specified for String#encode, replace
invalid byte sequence even if the destination encoding equals to
the source encoding.
* Symbol
* All symbols are now frozen.
* pack/unpack (Array/String)
* Q! and q! directives for long long type if platform has the type.
* toplevel
* extended methods:
* main.using is no longer experimental. The method activates refinements
in the ancestors of the argument module to support refinement
inheritance by Module#include.
=== Core classes compatibility issues (excluding feature bug fixes)
* IO
* incompatible changes:
* open ignore internal encoding if external encoding is ASCII-8BIT.
* Kernel#eval, Kernel#instance_eval, and Module#module_eval.
* Copies the scope information of the original environment, which means
that private, protected, public, and module_function without arguments
do not affect the environment outside the eval string.
For example, `class Foo; eval "private"; def foo; end; end' doesn't make
Foo#foo private.
* Kernel#untrusted?, untrust, and trust
* These methods are deprecated and their behavior is same as tainted?,
taint, and untaint, respectively. If $VERBOSE is true, they show warnings.
* Module#ancestors
* The ancestors of a singleton class now include singleton classes,
in particular itself.
* Module#define_method and Object#define_singleton_method
* Now they return the symbols of the defined methods, not the methods/procs
themselves.
* Numeric#quo
* Raises TypeError instead of ArgumentError if the receiver doesn't have
to_r method.
* Proc
* Returning from lambda proc now always exits from the Proc, not from the
method where the lambda is created. Returing from non-lambda proc exits
from the method, same as the former behavior.
=== Stdlib updates (outstanding ones only)
* CGI::Util
* All class methods modulized.
* Digest
* extended methods:
* Digest::Class.file takes optional arguments for its constructor
* Matrix
* Added Vector#cross_product.
* Net::SMTP
* Added Net::SMTP#rset to implement the RSET command
* Pathname
* New methods:
* Pathname#write
* Pathname#binwrite
* OpenSSL::BN
* extended methods:
* OpenSSL::BN.new allows Fixnum/Bignum argument.
* open-uri
* Support multiple fields with same field name (like Set-Cookie).
* RDoc
* Updated to 4.1.0.preview.1. Major enhancements include a modified default
template and accessibility enhancements.
For a list of minor enhancements and bug fixes see:
https://github.com/rdoc/rdoc/blob/v4.1.0.preview.1/History.rdoc
* Resolv
* New methods:
* Resolv::DNS.fetch_resource
* One-shot multicast DNS support
* Support LOC resources
* REXML::Parsers::SAX2Parser
* Fixes wrong number of arguments of entitydecl event. Document of the event
says "an array of the entity declaration" but implemenation passes two
or more arguments. It is an implementation bug but it breaks backword
compatibility.
* REXML::Parsers::StreamParser
* Supports "entity" event.
* REXML::Text
* REXML::Text#<< supports method chain like 'text << "XXX" << "YYY"'.
* REXML::Text#<< supports not "raw" mode.
* Rinda::RingServer, Rinda::RingFinger
* Rinda now supports multicast sockets. See Rinda::RingServer and
Rinda::RingFinger for details.
* RubyGems
* Updated to 2.2.0.preview.1 For a list of enhancements and bug fixes see:
https://github.com/rubygems/rubygems/blob/v2.2.0.preview.1/History.txt
* Set
* New methods:
* Set#intersect?
* Set#disjoint?
* Socket
* New methods:
* Socket.getifaddrs
* StringScanner
* extended methods:
* StringScanner#[] supports named captures.
* Syslog::Logger
* Added facility.
* Tempfile
* New methods:
* Tempfile.create
* WEBrick
* The body of a response may now be a StringIO or other IO-like that responds
to #readpartial and #read.
* XMLRPC::Client
* New methods:
* XMLRPC::Client#http. It returns Net::HTTP for the client. Normally,
it is not needed. It is useful when you want to change minor HTTP client
options. You can change major HTTP client options by XMLRPC::Client
methods. You should use XMLRPC::Client methods for changing major
HTTP client options instead of XMLRPC::Client#http.
=== Stdlib compatibility issues (excluding feature bug fixes)
* objspace
* new method:
* ObjectSpace.trace_object_allocations
* ObjectSpace.trace_object_allocations_start
* ObjectSpace.trace_object_allocations_stop
* ObjectSpace.trace_object_allocations_clear
* ObjectSpace.allocation_sourcefile
* ObjectSpace.allocation_sourceline
* ObjectSpace.allocation_class_path
* ObjectSpace.allocation_method_id
* ObjectSpace.allocation_generation
* Set
* incompatible changes:
* Set#to_set now returns self instead of generating a copy.
* URI
* incompatible changes:
* URI.decode_www_form follows current WHATWG URL Standard.
It gets encoding argument to specify the character encoding.
It now allows loose percent encoded strings, but denies ;-separator.
* URI.encode_www_form follows current WHATWG URL Standard.
It gets encoding argument to convert before percent encode.
UTF-16 strings aren't converted to UTF-8 before percent encode by default.
=== Built-in global variables compatibility issues
* $SAFE
* $SAFE=4 is obsolete. If $SAFE is set to 4 or larger, an ArgumentError
is raised.
* objspace
* new method:
* ObjectSpace.trace_object_allocations
* ObjectSpace.trace_object_allocations_start
* ObjectSpace.trace_object_allocations_stop
* ObjectSpace.trace_object_allocations_clear
* ObjectSpace.allocation_sourcefile
* ObjectSpace.allocation_sourceline
* ObjectSpace.allocation_class_path
* ObjectSpace.allocation_method_id
* ObjectSpace.allocation_generation
ObjectSpace.trace_object_allocations
ObjectSpace.trace_object_allocations_start
ObjectSpace.trace_object_allocations_stop
ObjectSpace.trace_object_allocations_clear
...
GitHub.preload_all
GC.start
count = ObjectSpace.count_objects
puts count[:TOTAL] - count[:FREE]
#=> 605183
::trace_object_allocations
# example.rb
1 class MyClass
2 def an_array
3 return [2,3,5,7,11,13,17,19,23,29,31]
4 end
5 def a_string
6 return "a String"
7 end
8 end
require 'objspace'
a = s = nil
ObjectSpace.trace_object_allocations do
a = MyClass.new.an_array
s = MyClass.new.a_string
end
ObjectSpace.allocation_sourcefile(a) #=> "example.rb"
ObjectSpace.allocation_sourceline(a) #=> 3
ObjectSpace.allocation_class_path(a) #=> "MyClass"
ObjectSpace.allocation_method_id(a) #=> "an_array"
ObjectSpace.allocation_sourcefile(s) #=> "example.rb"
ObjectSpace.allocation_sourceline(s) #=> 6
ObjectSpace.allocation_class_path(s) #=> "MyClass"
ObjectSpace.allocation_method_id(s) #=> "a_string"
require 'objspace'
ObjectSpace.trace_object_allocations_start
a = MyClass.new.an_array
s = MyClass.new.a_string
ObjectSpace.trace_object_allocations_stop
ObjectSpace.allocation_sourcefile(a) #=> "example.rb"
ObjectSpace.allocation_sourceline(a) #=> 3
ObjectSpace.allocation_class_path(a) #=> "MyClass"
ObjectSpace.allocation_method_id(a) #=> "an_array"
ObjectSpace.allocation_sourcefile(s) #=> "example.rb"
ObjectSpace.allocation_sourceline(s) #=> 6
ObjectSpace.allocation_class_path(s) #=> "MyClass"
ObjectSpace.allocation_method_id(s) #=> "a_string"
requires Ruby 2.1
1 class MyClass
2 def my_method
3 @hash = {2 => "foo", 3 => "bar", 5 => "baz"}
4 @string = "quux"
5 end
6 end
7
8 require "allocation_stats"
9 stats = AllocationStats.trace do
10 MyClass.new.my_method
11 end
12
13 puts stats.allocations.to_text
sourcefile sourceline class_path method_id class
-------------------------------- ---------- ---------- --------- -------
./examples/trace_my_class_raw.rb 4 MyClass my_method String
./examples/trace_my_class_raw.rb 3 MyClass my_method Hash
./examples/trace_my_class_raw.rb 3 MyClass my_method String
./examples/trace_my_class_raw.rb 3 MyClass my_method String
./examples/trace_my_class_raw.rb 3 MyClass my_method String
./examples/trace_my_class_raw.rb 10 Class new MyClass
1 class MyClass
2 def my_method
3 @hash = {2 => "foo", 3 => "bar", 5 => "baz"}
4 @string = "quux"
5 end
6 end
7
8 require "allocation_stats"
9 stats = AllocationStats.trace do
10 MyClass.new.my_method
11 end
12
13 puts stats.allocations.group_by(:sourcefile, :sourceline, :class).to_text
sourcefile sourceline class count
------------------------------------- ---------- ------- -----
./examples/trace_my_class_group_by.rb 4 String 1
./examples/trace_my_class_group_by.rb 3 Hash 1
./examples/trace_my_class_group_by.rb 3 String 3
./examples/trace_my_class_group_by.rb 10 MyClass 1
require "yaml"
require "allocation_stats"
stats = AllocationStats.trace do
# lots of objects from Rbconfig::CONFIG["rubylibdir"]
y = YAML.dump(["one string", "two string"])
end
puts stats.allocations(alias_paths: true).group_by(:sourcefile, :class).to_text
sourcefile class count
---------------------------------------- ------------------------------ -----
<RUBYLIBDIR>/psych/visitors/visitor.rb String 38
<RUBYLIBDIR>/psych/visitors/visitor.rb MatchData 5
<RUBYLIBDIR>/psych/visitors/visitor.rb Regexp 1
<RUBYLIBDIR>/psych/visitors/emitter.rb Psych::Emitter 1
<RUBYLIBDIR>/psych/visitors/emitter.rb Array 2
<RUBYLIBDIR>/psych/nodes/node.rb Psych::Visitors::Emitter 1
<RUBYLIBDIR>/psych/nodes/node.rb StringIO 1
<RUBYLIBDIR>/psych/nodes/node.rb String 3
<RUBYLIBDIR>/psych/tree_builder.rb Psych::Nodes::Scalar 2
<RUBYLIBDIR>/psych/visitors/yaml_tree.rb Array 12
<RUBYLIBDIR>/psych/visitors/yaml_tree.rb Method 5
<RUBYLIBDIR>/psych/scalar_scanner.rb String 5
<RUBYLIBDIR>/psych/scalar_scanner.rb MatchData 2
...
require "yaml"
require "allocation_stats"
stats = AllocationStats.trace do
# lots of objects from Rbconfig::CONFIG["rubylibdir"]
y = YAML.dump(["one string", "two string"])
end
puts stats.allocations(alias_paths: true).
group_by(:sourcefile, :class).
sort_by_count.
to_text
sourcefile class count
----------------------------------------- ------------------------------ -----
<RUBYLIBDIR>/psych/visitors/visitor.rb String 38
<RUBYLIBDIR>/psych/visitors/yaml_tree.rb String 21
<RUBYLIBDIR>/psych/visitors/yaml_tree.rb Array 12
<RUBYLIBDIR>/psych/visitors/yaml_tree.rb Method 5
<RUBYLIBDIR>/psych/scalar_scanner.rb String 5
<RUBYLIBDIR>/psych/visitors/visitor.rb MatchData 5
<RUBYLIBDIR>/psych/visitors/yaml_tree.rb Hash 3
<RUBYLIBDIR>/psych/nodes/node.rb String 3
<RUBYLIBDIR>/psych/nodes/node.rb Array 3
<RUBYLIBDIR>/psych/visitors/yaml_tree.rb MatchData 3
<RUBYLIBDIR>/psych/visitors/emitter.rb String 3
...
require 'hike'
require 'allocation_stats'
stats = AllocationStats.trace do
path = $:.detect { |p| p =~ /hike/ }
path = File.dirname(path)
trail = Hike::Trail.new path
trail.append_extension ".rb"
trail.append_paths "lib"
trail.find("hike")
end
puts stats.allocations(alias_paths: true)
.group_by(:sourcefile, :class_plus)
.sort_by_count
.to_text
sourcefile class_plus count
------------------------------------------------- --------------------------- -----
<RUBYLIBDIR>/rubygems/core_ext/kernel_require.rb String 438
<RUBYLIBDIR>/pathname.rb String 152
<RUBYLIBDIR>/rubygems/core_ext/kernel_require.rb Array<Fixnum,FalseClass> 134
<RUBYLIBDIR>/rubygems/core_ext/kernel_require.rb RubyVM::InstructionSequence 105
examples/hike_hike.rb String 81
<RUBYLIBDIR>/pathname.rb Array<String> 67
<RUBYLIBDIR>/pathname.rb String 67
<RUBYLIBDIR>/rubygems/core_ext/kernel_require.rb Array<Array> 58
<RUBYLIBDIR>/rubygems/core_ext/kernel_require.rb Array 47
<RUBYLIBDIR>/rubygems.rb String 27
<GEMDIR>/gems/hike-1.2.3/lib/hike/index.rb String 21
examples/hike_hike.rb RubyVM::InstructionSequence 20
<RUBYLIBDIR>/pathname.rb String 20
examples/hike_hike.rb Array 16
<GEMDIR>/gems/hike-1.2.3/lib/hike/index.rb String 15
...
require 'hike'
require 'allocation_stats'
stats = AllocationStats.new(burn: 1).trace do
path = $:.detect { |p| p =~ /hike/ }
path = File.dirname(path)
trail = Hike::Trail.new path
trail.append_extension ".rb"
trail.append_paths "lib"
trail.find("hike")
end
puts stats.allocations(alias_paths: true)
.group_by(:sourcefile, :class_plus)
.sort_by_count
.to_text
sourcefile class_plus count
----------------------------------------------------- --------------- -----
<RUBYLIBDIR>/pathname.rb String 287
<RUBYLIBDIR>/pathname.rb Array<String> 73
<GEMDIR>/gems/hike-1.2.3/lib/hike/index.rb String 73
<RUBYLIBDIR>/pathname.rb MatchData 13
<GEMDIR>/gems/hike-1.2.3/lib/hike/index.rb Pathname 12
<GEMDIR>/gems/hike-1.2.3/lib/hike/index.rb Array<Pathname> 11
<GEMDIR>/gems/hike-1.2.3/lib/hike/paths.rb String 7
<GEMDIR>/gems/hike-1.2.3/lib/hike/index.rb Array<String> 6
<GEMDIR>/gems/hike-1.2.3/lib/hike/index.rb MatchData 6
<GEMDIR>/gems/hike-1.2.3/lib/hike/trail.rb String 6
<GEMDIR>/gems/hike-1.2.3/lib/hike/trail.rb Array<String> 5
<GEMDIR>/gems/hike-1.2.3/lib/hike/index.rb Hash 5
...
# top of your spec_helper.rb
require 'allocation_stats'
AllocationStats.trace_rspec
mail$ be rspec spec/mail
...
Finished in 4 minutes 42.52 seconds
1469 examples, 0 failures, 11 pending
...
Top 10 allocation sites:
String allocations at /lib/mail/utilities.rb:180
4639 allocations during ./spec/mail/attachments_list_spec.rb:312
4443 allocations during ./spec/mail/message_spec.rb:1627
3975 allocations during ./spec/mail/network/retriever_methods/test_retriever_spec.rb:78
Array allocations at /lib/mail/parsers/received_parser.rb:13
2326 allocations during ./spec/mail/message_spec.rb:1627
1690 allocations during ./spec/mail/example_emails_spec.rb:300
...
Total allocations: 855826
class SinatraTemplatesApp < Sinatra::Base
HELLOS = ["Hello", "Hola", "Bonjour", "Guten Tag",
"こんにちは", "привет"]
enable :inline_templates
get "/erb" do
erb :erb
end
end
__END__
@@ erb
<html>
<body>
<ul id="hi">
<% HELLOS.each do |hello| %>
<li class="greeting"><%= hello %> World!</li>
<% end %>
</ul>
</body>
</html>
Rack AllocationStats help Append ras[trace]=true to your URL to trace all object allocations during the request. The server will respond with statistics on the allocations, instead of the application's response. Options ras[times]=COUNT send the request to the application COUNT times, to reduce statistics from initial allocations that don't happen on repeat requests. ras[help] immediately respond with this help text ras[scope]=SCOPE limits the list of allocations in the response to those whose `sourcefile` matches SCOPE. `ras[scope]='.'` is a special case which is expanded to be the current working directory. ...
Use self-modifying collection methods where possible.
diff --git a/lib/temple/hash.rb b/lib/temple/hash.rb
index a2235c0..f1e5a70 100644
--- a/lib/temple/hash.rb
+++ b/lib/temple/hash.rb
@@ -24,3 +24,3 @@ def each
def keys
- @hash.inject([]) {|keys, h| keys += h.keys }.uniq
+ @hash.inject([]) {|keys, h| keys.concat(h.keys) }.uniq
end
(Especially String-building)
String literals, when frozen, will always refer to the same object.
STRING = "This is a static string"
def no_freeze
STRING.tr(" ", "_") << "not frozen"
end
def freeze
STRING.tr(" ".freeze, "_".freeze) << "frozen".freeze
end
user system total real gc allocations
9.380 0.100 9.480 ( 9.502) 1.724 1600000
7.110 0.050 7.160 ( 7.190) 1.098 400000
80 def run_callbacks(kind, *args, &block)
81 send("_run_#{kind}_callbacks", *args, &block)
82 end
...
413 def __callback_runner_name(key, kind)
414 "_run__#{self.name.hash.abs}__#{kind}__#{key.hash.abs}__callbacks"
415 end
383 def __callback_runner_name_cache
384 @__callback_runner_name_cache ||= ThreadSafe::Cache.new {|cache, kind|
cache[kind] = __generate_callback_runner_name(kind) }
385 end
386
387 def __generate_callback_runner_name(kind)
388 "_run__#{self.name.hash.abs}__#{kind}__callbacks"
389 end
390
391 def __callback_runner_name(kind)
392 __callback_runner_name_cache[kind]
393 end
6 class ActiveRecord::Relation
7 JoinOperation = Struct.new(:relation, :join_class, :on)
8 ASSOCIATION_METHODS = [:includes, :eager_load, :preload]
9 MULTI_VALUE_METHODS = [:select, :group, :order, :joins, :where, :having, :bind]
10 SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
:reverse_order, :uniq]
... 19 def initialize(klass, table)
... 26 SINGLE_VALUE_METHODS.each {|v| instance_variable_set(:"@#{v}_value", nil)}
27 (ASSOCIATION_METHODS + MULTI_VALUE_METHODS).each {|v|
instance_variable_set(:"@#{v}_values", [])}
...
30 end
action_view/helpers/tag_helper.rb:65
64 def tag(name, options = nil, open = false, escape = true)
65 "<#{name}#{tag_options(options, escape) if options}#{open ? ">" : "/>"}".html_safe
66 end
106 def each
107 loop do
108 val = step
109 break self if done?
110 yield val
111 end
112 end
#step
?::trace_object_allocations
to your toolbox.