Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 760268b80847
Choose a base ref
...
head repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 17c829d772d4
Choose a head ref
  • 2 commits
  • 3 files changed
  • 1 contributor

Commits on Nov 30, 2016

  1. Fixed incorrect MatchData docs. Fixes #3606

    Ary Borenszweig committed Nov 30, 2016

    Verified

    This commit was signed with the committer’s verified signature.
    headius Charles Oliver Nutter
    Copy the full SHA
    c6159b1 View commit details
  2. Pretty print: call inspect if redefined

    This is similar to Ruby and it does make sense.
    Ary Borenszweig committed Nov 30, 2016
    Copy the full SHA
    17c829d View commit details
Showing with 71 additions and 68 deletions.
  1. +22 −18 src/reference.cr
  2. +29 −36 src/regex/match_data.cr
  3. +20 −14 src/struct.cr
40 changes: 22 additions & 18 deletions src/reference.cr
Original file line number Diff line number Diff line change
@@ -70,26 +70,30 @@ class Reference
end

def pretty_print(pp) : Nil
prefix = "#<#{{{@type.name.id.stringify}}}:0x#{object_id.to_s(16)}"
executed = exec_recursive(:pretty_print) do
pp.surround(prefix, ">", left_break: " ", right_break: nil) do
{% for ivar, i in @type.instance_vars.map(&.name).sort %}
{% if i > 0 %}
pp.comma
{% end %}
pp.group do
pp.text "@{{ivar.id}}="
pp.nest do
pp.breakable ""
@{{ivar.id}}.pretty_print(pp)
{% if @type.methods.any? &.name.==("inspect") %}
pp.text inspect
{% else %}
prefix = "#<#{{{@type.name.id.stringify}}}:0x#{object_id.to_s(16)}"
executed = exec_recursive(:pretty_print) do
pp.surround(prefix, ">", left_break: " ", right_break: nil) do
{% for ivar, i in @type.instance_vars.map(&.name).sort %}
{% if i > 0 %}
pp.comma
{% end %}
pp.group do
pp.text "@{{ivar.id}}="
pp.nest do
pp.breakable ""
@{{ivar.id}}.pretty_print(pp)
end
end
end
{% end %}
{% end %}
end
end
end
unless executed
pp.text "#{prefix} ...>"
end
unless executed
pp.text "#{prefix} ...>"
end
{% end %}
end

def to_s(io : IO) : Nil
65 changes: 29 additions & 36 deletions src/regex/match_data.cr
Original file line number Diff line number Diff line change
@@ -3,15 +3,8 @@ class Regex
# returned by `Regex#match` and `String#match`. It encapsulates all the
# results of a regular expression match.
#
# `Regex#match` and `String#match` can return `nil`, to represent an
# unsuccessful match, but there are overloads of both methods that accept a
# block. These overloads are convenient to access the `Regex::MatchData` of a
# successful match, since the block argument can't be `nil`.
#
# ```
# "Crystal".match(/[p-s]/).size # => undefined method 'size' for Nil
#
# "Crystal".match(/[p-s]/) do |md|
# if md = "Crystal".match(/[p-s]/)
# md.string # => "Crystal"
# md[0] # => "r"
# md[1]? # => nil
@@ -26,23 +19,23 @@ class Regex
# Returns the original regular expression.
#
# ```
# "Crystal".match(/[p-s]/) { |md| md.regex } # => /[p-s]/
# "Crystal".match(/[p-s]/).not_nil!.regex # => /[p-s]/
# ```
getter regex : Regex

# Returns the number of capture groups, including named capture groups.
#
# ```
# "Crystal".match(/[p-s]/) { |md| md.size } # => 0
# "Crystal".match(/r(ys)/) { |md| md.size } # => 1
# "Crystal".match(/r(ys)(?<ok>ta)/) { |md| md.size } # => 2
# "Crystal".match(/[p-s]/).not_nil!.size # => 0
# "Crystal".match(/r(ys)/).not_nil!.size # => 1
# "Crystal".match(/r(ys)(?<ok>ta)/).not_nil!.size # => 2
# ```
getter size : Int32

# Returns the original string.
#
# ```
# "Crystal".match(/[p-s]/) { |md| md.string } # => "Crystal"
# "Crystal".match(/[p-s]/).not_nil!.string # => "Crystal"
# ```
getter string : String

@@ -56,9 +49,9 @@ class Regex
# Otherwise, uses the match of the `n`th capture group.
#
# ```
# "Crystal".match(/r/) { |md| md.begin(0) } # => 1
# "Crystal".match(/r(ys)/) { |md| md.begin(1) } # => 2
# "クリスタル".match(/リ(ス)/) { |md| md.begin(0) } # => 1
# "Crystal".match(/r/).not_nil!.begin(0) # => 1
# "Crystal".match(/r(ys)/).not_nil!.begin(1) # => 2
# "クリスタル".match(/リ(ス)/).not_nil!.begin(0) # => 1
# ```
def begin(n = 0)
@string.byte_index_to_char_index byte_begin(n)
@@ -70,9 +63,9 @@ class Regex
# Otherwise, uses the match of the `n`th capture group.
#
# ```
# "Crystal".match(/r/) { |md| md.end(0) } # => 2
# "Crystal".match(/r(ys)/) { |md| md.end(1) } # => 4
# "クリスタル".match(/リ(ス)/) { |md| md.end(0) } # => 3
# "Crystal".match(/r/).not_nil!.end(0) # => 2
# "Crystal".match(/r(ys)/).not_nil!.end(1) # => 4
# "クリスタル".match(/リ(ス)/).not_nil!.end(0) # => 3
# ```
def end(n = 0)
@string.byte_index_to_char_index byte_end(n)
@@ -84,9 +77,9 @@ class Regex
# Otherwise, uses the match of the `n`th capture group.
#
# ```
# "Crystal".match(/r/) { |md| md.byte_begin(0) } # => 1
# "Crystal".match(/r(ys)/) { |md| md.byte_begin(1) } # => 4
# "クリスタル".match(/リ(ス)/) { |md| md.byte_begin(0) } # => 3
# "Crystal".match(/r/).not_nil!.byte_begin(0) # => 1
# "Crystal".match(/r(ys)/).not_nil!.byte_begin(1) # => 4
# "クリスタル".match(/リ(ス)/).not_nil!.byte_begin(0) # => 3
# ```
def byte_begin(n = 0)
check_index_out_of_bounds n
@@ -99,9 +92,9 @@ class Regex
# Otherwise, uses the match of the `n`th capture group.
#
# ```
# "Crystal".match(/r/) { |md| md.byte_end(0) } # => 2
# "Crystal".match(/r(ys)/) { |md| md.byte_end(1) } # => 4
# "クリスタル".match(/リ(ス)/) { |md| md.byte_end(0) } # => 9
# "Crystal".match(/r/).not_nil!.byte_end(0) # => 2
# "Crystal".match(/r(ys)/).not_nil!.byte_end(1) # => 4
# "クリスタル".match(/リ(ス)/).not_nil!.byte_end(0) # => 9
# ```
def byte_end(n = 0)
check_index_out_of_bounds n
@@ -114,9 +107,9 @@ class Regex
# When `n` is `0`, returns the match for the entire `Regex`.
#
# ```
# "Crystal".match(/r(ys)/) { |md| md[0]? } # => "rys"
# "Crystal".match(/r(ys)/) { |md| md[1]? } # => "ys"
# "Crystal".match(/r(ys)/) { |md| md[2]? } # => nil
# "Crystal".match(/r(ys)/).not_nil![0]? # => "rys"
# "Crystal".match(/r(ys)/).not_nil![1]? # => "ys"
# "Crystal".match(/r(ys)/).not_nil![2]? # => nil
# ```
def []?(n)
return unless valid_group?(n)
@@ -131,8 +124,8 @@ class Regex
# if there is no `n`th capture group.
#
# ```
# "Crystal".match(/r(ys)/) { |md| md[1] } # => "ys"
# "Crystal".match(/r(ys)/) { |md| md[2] } # => raises IndexError
# "Crystal".match(/r(ys)/).not_nil![1] # => "ys"
# "Crystal".match(/r(ys)/).not_nil![2] # => raises IndexError
# ```
def [](n)
check_index_out_of_bounds n
@@ -144,8 +137,8 @@ class Regex
# `nil` if there is no such named capture group.
#
# ```
# "Crystal".match(/r(?<ok>ys)/) { |md| md["ok"]? } # => "ys"
# "Crystal".match(/r(?<ok>ys)/) { |md| md["ng"]? } # => nil
# "Crystal".match(/r(?<ok>ys)/).not_nil!["ok"]? # => "ys"
# "Crystal".match(/r(?<ok>ys)/).not_nil!["ng"]? # => nil
# ```
def []?(group_name : String)
ret = LibPCRE.get_stringnumber(@code, group_name)
@@ -157,8 +150,8 @@ class Regex
# raises an `ArgumentError` if there is no such named capture group.
#
# ```
# "Crystal".match(/r(?<ok>ys)/) { |md| md["ok"] } # => "ys"
# "Crystal".match(/r(?<ok>ys)/) { |md| md["ng"] } # => raises ArgumentError
# "Crystal".match(/r(?<ok>ys)/).not_nil!["ok"] # => "ys"
# "Crystal".match(/r(?<ok>ys)/).not_nil!["ng"] # => raises ArgumentError
# ```
def [](group_name : String)
match = self[group_name]?
@@ -172,7 +165,7 @@ class Regex
# starts at the start of the string, returns the empty string.
#
# ```
# "Crystal".match(/yst/) { |md| md.pre_match } # => "Cr"
# "Crystal".match(/yst/).not_nil!.pre_match # => "Cr"
# ```
def pre_match
@string.byte_slice(0, byte_begin(0))
@@ -182,7 +175,7 @@ class Regex
# at the end of the string, returns the empty string.
#
# ```
# "Crystal".match(/yst/) { |md| md.post_match } # => "al"
# "Crystal".match(/yst/).not_nil!.post_match # => "al"
# ```
def post_match
@string.byte_slice(byte_end(0))
34 changes: 20 additions & 14 deletions src/struct.cr
Original file line number Diff line number Diff line change
@@ -108,21 +108,27 @@ struct Struct
end

def pretty_print(pp) : Nil
prefix = "#{{{@type.name.id.stringify}}}("
pp.surround(prefix, ")", left_break: "", right_break: nil) do
{% for ivar, i in @type.instance_vars.map(&.name).sort %}
{% if i > 0 %}
pp.comma
{% end %}
pp.group do
pp.text "@{{ivar.id}}="
pp.nest do
pp.breakable ""
@{{ivar.id}}.pretty_print(pp)
# TODO: do this better: ask if the type overrides
# the method from Struct
{% if @type.methods.any? &.name.==("inspect") %}
pp.text inspect
{% else %}
prefix = "#{{{@type.name.id.stringify}}}("
pp.surround(prefix, ")", left_break: "", right_break: nil) do
{% for ivar, i in @type.instance_vars.map(&.name).sort %}
{% if i > 0 %}
pp.comma
{% end %}
pp.group do
pp.text "@{{ivar.id}}="
pp.nest do
pp.breakable ""
@{{ivar.id}}.pretty_print(pp)
end
end
end
{% end %}
end
{% end %}
end
{% end %}
end

# Same as `#inspect(io)`.