>> a=*(1..10) => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Array()
method, provided by Kernel
, which tries to call to_ary
, then to_a
on its argument: Array(1..10) => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
to_a
method (1..10).to_a => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Array.new
: Array.new(100) {|i| i + 1} => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
$ ruby -e 'require "pp"; pp Array.new([*(1..10)])' --dump parsetree_with_comment ########################################################### ## Do NOT use this node dump for any purpose other than ## ## debug and research. Compatibility is not guaranteed. ## ########################################################### # @ NODE_SCOPE (line: 1) # | # new scope # | # format: [nd_tbl]: local table, [nd_args]: arguments, [nd_body]: body # +- nd_tbl (local table): (empty) # +- nd_args (arguments): # | (null node) # +- nd_body (body): # @ NODE_BLOCK (line: 1) # | # statement sequence # | # format: [nd_head]; [nd_next] # | # example: foo; bar # +- nd_head (current statement): # | @ NODE_FCALL (line: 1) # | | # function call # | | # format: [nd_mid]([nd_args]) # | | # example: foo(1) # | +- nd_mid (method id): :require # | +- nd_args (arguments): # | @ NODE_ARRAY (line: 1) # | | # array constructor # | | # format: [ [nd_head], [nd_next].. ] (length: [nd_alen]) # | | # example: [1, 2, 3] # | +- nd_alen (length): 1 # | +- nd_head (element): # | | @ NODE_STR (line: 1) # | | | # string literal # | | | # format: [nd_lit] # | | | # example: 'foo' # | | +- nd_lit (literal): "pp" # | +- nd_next (next element): # | (null node) # +- nd_next (next block): # @ NODE_BLOCK (line: 1) # | # statement sequence # | # format: [nd_head]; [nd_next] # | # example: foo; bar # +- nd_head (current statement): # | @ NODE_FCALL (line: 1) # | | # function call # | | # format: [nd_mid]([nd_args]) # | | # example: foo(1) # | +- nd_mid (method id): :pp # | +- nd_args (arguments): # | @ NODE_ARRAY (line: 1) # | | # array constructor # | | # format: [ [nd_head], [nd_next].. ] (length: [nd_alen]) # | | # example: [1, 2, 3] # | +- nd_alen (length): 1 # | +- nd_head (element): # | | @ NODE_CALL (line: 1) # | | | # method invocation # | | | # format: [nd_recv].[nd_mid]([nd_args]) # | | | # example: obj.foo(1) # | | +- nd_mid (method id): :new # | | +- nd_recv (receiver): # | | | @ NODE_CONST (line: 1) # | | | | # constant reference # | | | | # format: [nd_vid](constant) # | | | | # example: X # | | | +- nd_vid (local variable): :Array # | | +- nd_args (arguments): # | | @ NODE_ARRAY (line: 1) # | | | # array constructor # | | | # format: [ [nd_head], [nd_next].. ] (length: [nd_alen]) # | | | # example: [1, 2, 3] # | | +- nd_alen (length): 1 # | | +- nd_head (element): # | | | @ NODE_SPLAT (line: 1) # | | | | # splat argument # | | | | # format: *[nd_head] # | | | | # example: foo(*ary) # | | | +- nd_head (splat'ed array): # | | | @ NODE_LIT (line: 1) # | | | | # literal # | | | | # format: [nd_lit] # | | | | # example: 1, /foo/ # | | | +- nd_lit (literal): 1..10 # | | +- nd_next (next element): # | | (null node) # | +- nd_next (next element): # | (null node) # +- nd_next (next block): # (null node)
Możemy zażyczyć sobie również listę wykonywanych instrukcji przez VM:
$ ruby -e 'require "pp"; pp Array.new([*(1..10)])' --dump insns == disasm: <RubyVM::InstructionSequence:<main>@-e>====================== 0000 trace 1 ( 1) 0002 putself 0003 putstring "pp" 0005 send :require, 1, nil, 8, <ic:0> 0011 pop 0012 trace 1 0014 putself 0015 getinlinecache 22, <ic:1> 0018 getconstant :Array 0020 setinlinecache <ic:1> 0022 trace 1 0024 putobject 1..10 0026 splatarray true 0028 send :new, 1, nil, 0, <ic:2> 0034 send :pp, 1, nil, 8, <ic:3> 0040 leave
Można też zobaczyć jak działa parser Ruby'ego:
$ ruby -e 'require "pp"; pp Array.new([*(1..10)])' --dump yydebug Starting parse Entering state 0 Reducing stack by rule 1 (line 782): -> $$ = nterm @1 () Stack now 0 Entering state 2 Reading a token: Next token is token tIDENTIFIER () Shifting token tIDENTIFIER () Entering state 35 Reading a token: Next token is token tSTRING_BEG () Reducing stack by rule 547 (line 4818): $1 = token tIDENTIFIER () -> $$ = nterm operation () Stack now 0 2 Entering state 110 Next token is token tSTRING_BEG () [...]
Za pomocą tej metody, dostępnej większości kolekcji, można spróbować pobrać dany element, a w wypadku jego braku uruchomić zdefiniowaną akcję. Gdy nie podamy bloku, podniesie wyjątek.
TODO: Napisać jakiś przykład!
# Wartość standardowa width = options.fetch(:width) {40} # Podnoszenie wyjątku opt = {}.fetch(:required_opt) do raise ArgumentError, "Missing option!" end
Range#include?
iteruje od min
do szukanej wartości (lub max
). Przy dużych zasięgach, jest to bardzo wolne (O(N)
zamiast O(1)
). Możemy skorzystać z Range#cover?
, która porównuje tylko największą i najmniejszą wartość z szukaną wartością.
#!/usr/bin/env ruby -wKU require 'date' require 'benchmark' start_date = Date.strptime('1410-07-15', '%Y-%m-%d') end_date = Date.strptime('2012-12-12', '%Y-%m-%d') date = Date.strptime('2011-12-12', '%Y-%m-%d') range = (start_date..end_date) Benchmark.bmbm do |results| results.report("include?") { range.include?(date) } results.report("cover?") { range.cover?(date) } end
Output:
Rehearsal -------------------------------------------- include? 0.430000 0.010000 0.440000 ( 0.441153) cover? 0.000000 0.000000 0.000000 ( 0.000009) ----------------------------------- total: 0.440000sec user system total real include? 0.430000 0.000000 0.430000 ( 0.502014) cover? 0.000000 0.000000 0.000000 ( 0.000013)
> Project.first.method(:name).call => "Server Abloesung"
> User.last.method(:address).source_location => ["/home/sqbell/.rvm/gems/ruby-1.9.3-p392/gems/mongoid-3.1.4/lib/mongoid/fields.rb", 388]
::Rails::Engine # absolute path to the constant Rails::Engine # path relative to the current tree level
SEE: http://stackoverflow.com/questions/10482772/rubys-double-colon-operator-usage-differences
hsh = Hash.new([]) hsh[:a].push(1, 2, 3) # => [1, 2, 3] # So far, so good hsh[:b].push(4, 5, 6) # => [1, 2, 3, 4, 5, 6] # LOLWUT?! hsh[:a] # => [1, 2, 3, 4, 5, 6] hsh[:b] # => [1, 2, 3, 4, 5, 6]
Ta sama, pusta, tablica jest przekazywana! Spróbujmy jeszcze raz:
hsh = Hash.new { [] } hsh[:a].push(1, 2, 3) # => [1, 2, 3] hsh[:b].push(4, 5, 6) # => [4, 5, 6] hsh[:c] << 7 # => [7] hsh[:a] # => [] hsh[:b] # => [] hsh[:c] # => []
Ciągle coś jest nie tak. Za każdym razem, gdy próbujemy się dostać do wartości klucza, który nie istnieje, wykonywany jest kod przekazanego bloku. Wartość dodawana jest do tablicy, ale tablica nie jest nigdzie przypisywana, więc jest czyszczona przez GC
.
hsh = Hash.new { |hash, key| hash[key] = [] } # => {} hsh[:a].push(1, 2, 3) # => [1, 2, 3] hsh[:b].push(4, 5, 6) # => [4, 5, 6] hsh[:c] << 7 # => [7] hsh[:a] # => [1, 2, 3] hsh[:b] # => [4, 5, 6] hsh[:c] # => [7]
SEE: http://stackoverflow.com/questions/2552579/ruby-method-array-not-updating-the-array-in-hash
Druga z tych metod dodana została dopiero w Rubym 2.2.
> [1, 'a', 2, 'b', 'c', 3, 'd', 'e', 'f'].slice_before { |e| e.is_a?(Integer) }.to_a #=> [[1, "a"], [2, "b", "c"], [3, "d", "e", "f"]]
Zamiast bloku, możemy podać argument. Będzie on porównany za pomocą ===
. Zatem powyższy przykład można zapisać róœnież nastęþująco:
> [1, 'a', 2, 'b', 'c', 3, 'd', 'e', 'f'].slice_before(Integer).to_a
#slice_after:
> [1, 'a', 2, 'b', 'c', 3, 'd', 'e', 'f'].slice_after(Integer).to_a #=> [[1], ["a", 2], ["b", "c", 3], ["d", "e", "f"]]
#slice_when można wykorzystać do szukania następujących po sobie liczb:
> [1, 3, 4, 5, 7, 8, 9, 10, 12].slice_when { |a, b| a + 1 != b }.to_a #=> [[1], [3, 4, 5], [7, 8, 9, 10], [12]]