├── .document ├── .gitignore ├── .travis.yml ├── Gemfile ├── HISTORY.txt ├── LICENSE ├── README.rdoc ├── Rakefile ├── lib ├── sourcify.rb └── sourcify │ ├── common │ ├── parser │ │ ├── converter.rb │ │ ├── raw_scanner │ │ │ ├── comment.rb │ │ │ ├── counter.rb │ │ │ ├── dstring.rb │ │ │ ├── extensions.rb │ │ │ └── heredoc.rb │ │ └── source_code.rb │ └── ragel │ │ ├── common.rl │ │ ├── expressions.rl │ │ └── machines.rl │ ├── errors.rb │ ├── method.rb │ ├── method │ ├── methods.rb │ ├── methods │ │ ├── to_raw_source.rb │ │ ├── to_sexp.rb │ │ └── to_source.rb │ ├── parser.rb │ └── parser │ │ ├── converter.rb │ │ ├── raw_scanner.rb │ │ ├── raw_scanner.rl │ │ ├── raw_scanner_extensions.rb │ │ ├── scanner.rb │ │ └── source_code.rb │ ├── patches.rb │ ├── proc.rb │ ├── proc │ ├── methods.rb │ ├── methods │ │ ├── source_location.rb │ │ ├── to_raw_source.rb │ │ ├── to_sexp.rb │ │ └── to_source.rb │ ├── parser.rb │ └── parser │ │ ├── converter.rb │ │ ├── normalizer.rb │ │ ├── raw_scanner.rb │ │ ├── raw_scanner.rl │ │ ├── raw_scanner_extensions.rb │ │ ├── scanner.rb │ │ └── source_code.rb │ └── version.rb ├── sourcify.gemspec └── spec ├── dump_object_space_procs.rb ├── method ├── encoding_from_def_end_block_spec.rb ├── encoding_from_define_method_spec.rb ├── others_from_def_end_block_spec.rb ├── others_from_define_method_spec.rb ├── raw_scanner │ ├── block_comment_spec.rb │ ├── double_colons_spec.rb │ ├── double_quote_str_w_interpolation_spec.rb │ ├── double_quote_str_wo_interpolation_spec.rb │ ├── heredoc_w_indent_spec.rb │ ├── heredoc_wo_indent_spec.rb │ ├── kw_block_start_alias1_spec.rb │ ├── kw_block_start_alias2_spec.rb │ ├── per_line_comment_spec.rb │ ├── single_quote_str_spec.rb │ ├── slash_operator_spec.rb │ └── spec_helper.rb ├── spec_helper.rb ├── to_raw_source_spec.rb ├── to_raw_source_w_specified_strip_enclosure_spec.rb ├── to_sexp_from_def_end_block_w_variables_spec.rb ├── to_sexp_from_def_end_block_within_irb_spec.rb ├── to_sexp_from_def_end_block_within_pry_spec.rb ├── to_sexp_from_define_method_w_multi_blocks_and_specified_attached_to_spec.rb ├── to_sexp_from_define_method_w_variables_spec.rb ├── to_sexp_from_define_method_within_irb_spec.rb ├── to_sexp_from_define_method_within_pry_spec.rb ├── to_sexp_w_specified_strip_enclosure_spec.rb ├── to_source_from_def_end_block_w_19_extras_spec.rb ├── to_source_from_def_end_block_w_nested_begin_spec.rb ├── to_source_from_def_end_block_w_nested_case_spec.rb ├── to_source_from_def_end_block_w_nested_class_spec.rb ├── to_source_from_def_end_block_w_nested_do_end_block_spec.rb ├── to_source_from_def_end_block_w_nested_for_spec.rb ├── to_source_from_def_end_block_w_nested_if_spec.rb ├── to_source_from_def_end_block_w_nested_literal_keyword_spec.rb ├── to_source_from_def_end_block_w_nested_method_spec.rb ├── to_source_from_def_end_block_w_nested_module_spec.rb ├── to_source_from_def_end_block_w_nested_unless_spec.rb ├── to_source_from_def_end_block_w_nested_until_spec.rb ├── to_source_from_def_end_block_w_nested_while_spec.rb ├── to_source_from_def_end_block_w_singleton_method_spec.rb ├── to_source_from_def_end_block_within_irb_spec.rb ├── to_source_from_def_end_block_within_pry_spec.rb ├── to_source_from_def_end_w_multi_blocks_and_many_matches_spec.rb ├── to_source_from_def_end_w_multi_blocks_and_single_match_spec.rb ├── to_source_from_define_method_w_braced_block_spec.rb ├── to_source_from_define_method_w_do_end_block_spec.rb ├── to_source_from_define_method_w_multi_blocks_and_many_matches_spec.rb ├── to_source_from_define_method_w_multi_blocks_and_single_match_spec.rb ├── to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_many_matches_spec.rb ├── to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_no_match_spec.rb ├── to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_single_match_spec.rb ├── to_source_from_define_method_w_multi_blocks_and_specified_attached_to_spec.rb ├── to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_many_matches_spec.rb ├── to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_no_match_spec.rb ├── to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_single_match_spec.rb ├── to_source_from_define_method_w_multi_blocks_and_specified_ignore_nested_spec.rb ├── to_source_from_define_method_within_irb_spec.rb ├── to_source_from_define_method_within_pry_spec.rb ├── to_source_magic_file_var_spec.rb ├── to_source_magic_line_var_spec.rb └── to_source_w_specified_strip_enclosure_spec.rb ├── no_method └── unsupported_platform_spec.rb ├── proc ├── 19x_extras.rb ├── created_on_the_fly_proc_spec.rb ├── encoding_spec.rb ├── others_spec.rb ├── raw_scanner │ ├── block_comment_spec.rb │ ├── double_colons_spec.rb │ ├── double_quote_str_w_interpolation_spec.rb │ ├── double_quote_str_wo_interpolation_spec.rb │ ├── heredoc_w_indent_spec.rb │ ├── heredoc_wo_indent_spec.rb │ ├── kw_block_start_alias1_spec.rb │ ├── kw_block_start_alias2_spec.rb │ ├── per_line_comment_spec.rb │ ├── single_quote_str_spec.rb │ ├── slash_operator_spec.rb │ └── spec_helper.rb ├── readme ├── spec_helper.rb ├── to_raw_source_spec.rb ├── to_raw_source_w_specified_strip_enclosure_spec.rb ├── to_sexp_from_multi_blocks_w_specified_attached_to_spec.rb ├── to_sexp_variables_spec.rb ├── to_sexp_w_specified_strip_enclosure_spec.rb ├── to_sexp_within_irb_spec.rb ├── to_sexp_within_pry_spec.rb ├── to_source_from_braced_block_w_nested_braced_block_spec.rb ├── to_source_from_braced_block_w_nested_hash_spec.rb ├── to_source_from_braced_block_wo_nesting_complication_spec.rb ├── to_source_from_do_end_block_w_nested_begin_spec.rb ├── to_source_from_do_end_block_w_nested_case_spec.rb ├── to_source_from_do_end_block_w_nested_class_spec.rb ├── to_source_from_do_end_block_w_nested_do_end_block_spec.rb ├── to_source_from_do_end_block_w_nested_for_spec.rb ├── to_source_from_do_end_block_w_nested_if_spec.rb ├── to_source_from_do_end_block_w_nested_literal_keyword_spec.rb ├── to_source_from_do_end_block_w_nested_method_spec.rb ├── to_source_from_do_end_block_w_nested_module_spec.rb ├── to_source_from_do_end_block_w_nested_unless_spec.rb ├── to_source_from_do_end_block_w_nested_until_spec.rb ├── to_source_from_do_end_block_w_nested_while_spec.rb ├── to_source_from_do_end_block_wo_nesting_complication_spec.rb ├── to_source_from_multi_blocks_w_many_matches_spec.rb ├── to_source_from_multi_blocks_w_single_match_spec.rb ├── to_source_from_multi_blocks_w_specified_attached_to_and_many_matches_spec.rb ├── to_source_from_multi_blocks_w_specified_attached_to_and_no_match_spec.rb ├── to_source_from_multi_blocks_w_specified_attached_to_and_single_match_spec.rb ├── to_source_from_multi_blocks_w_specified_attached_to_spec.rb ├── to_source_from_multi_blocks_w_specified_body_matcher_and_many_matches_spec.rb ├── to_source_from_multi_blocks_w_specified_body_matcher_and_no_match_spec.rb ├── to_source_from_multi_blocks_w_specified_body_matcher_and_single_match_spec.rb ├── to_source_from_multi_blocks_w_specified_ignore_nested_spec.rb ├── to_source_from_multi_do_end_blocks_w_single_match_spec.rb ├── to_source_magic_file_var_spec.rb ├── to_source_magic_line_var_spec.rb ├── to_source_variables_spec.rb ├── to_source_w_specified_strip_enclosure_spec.rb ├── to_source_within_irb_spec.rb └── to_source_within_pry_spec.rb ├── raw_scanner ├── block_comment_shared_spec.rb ├── double_colons_shared_spec.rb ├── double_quote_str_w_interpolation_shared_spec.rb ├── double_quote_str_wo_interpolation_shared_spec.rb ├── heredoc_w_indent_shared_spec.rb ├── heredoc_wo_indent_shared_spec.rb ├── kw_block_start_alias1_shared_spec.rb ├── kw_block_start_alias2_shared_spec.rb ├── per_line_comment_shared_spec.rb ├── shared_specs.rb ├── single_quote_str_shared_spec.rb └── slash_operator_shared_spec.rb ├── run_build.sh └── spec_helper.rb /.document: -------------------------------------------------------------------------------- 1 | README.rdoc 2 | lib/**/*.rb 3 | bin/* 4 | features/**/*.feature 5 | LICENSE 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## MAC OS 2 | .DS_Store 3 | 4 | ## TEXTMATE 5 | *.tmproj 6 | tmtags 7 | 8 | ## EMACS 9 | *~ 10 | \#* 11 | .\#* 12 | 13 | ## VIM 14 | *.swp 15 | 16 | ## PROJECT::GENERAL 17 | coverage 18 | rdoc 19 | pkg 20 | Gemfile.lock 21 | 22 | ## PROJECT::SPECIFIC 23 | .rvmrc 24 | tmp 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | script: ./spec/run_build.sh 3 | rvm: 4 | - 1.8.6 5 | - 1.8.7 6 | - 1.9.2 7 | - 1.9.3 8 | - jruby-18mode 9 | - jruby-19mode 10 | - ree 11 | env: 12 | - TRAVIS=true 13 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Specify your gem's dependencies in sourcify.gemspec 4 | gemspec 5 | 6 | # As required by travis, see 7 | # http://about.travis-ci.org/docs/user/languages/ruby 8 | group :test do 9 | gem 'rake' 10 | end 11 | -------------------------------------------------------------------------------- /HISTORY.txt: -------------------------------------------------------------------------------- 1 | === Current (pre 0.6.0) 2 | 3 | * adds Method#to_source, Method#to_sexp & Method#to_raw_source to MRI-1.9.2 (issue#3) 4 | * extensive refactoring to existing proc support to support the above 5 | * fixes incorrect encoding for scanner result (issue#19) [@tomykaira] 6 | * ensures compatibility with pry (issue#22) [@ty, @scooter-dangle] 7 | * fixes "already initialized const X" in ruby_parser" [@jmettraux] 8 | 9 | === 0.5.0 (May 2, 2011) 10 | 11 | * adds Proc#to_raw_source that supports extracting of raw code, as it is written in 12 | the source code (see issue#9), it supports all options that are already supported 13 | by Proc#to_source. 14 | * MRI-1.8.6 now supports both ParseTree & static-scanner mode 15 | * out with infinity_test (due to unresolvable & unexpected consistent failure in 16 | running specs for jruby-1.6.1 & always running ParseTree mode specs in static-scanner 17 | mode), use homebaked rake tasks (spec:parsetree, spec:static & spec:all) to acheive 18 | testing of different rubies in different modes 19 | * removd dependency on jeweler, & use bundler instead to handle dependency & also have 20 | our own handcrafted gemspec file 21 | 22 | === 0.4.2 (Feb 06, 2011) 23 | 24 | * fixes Sourcify::NoMatchingProcError when inline proc contains hashes (issue#7) [#ngty] 25 | * uses RubyParser#parse to eval correctness of code instead of Kernel#eval [#ngty] 26 | 27 | === 0.4.1 (Jan 29, 2011) 28 | 29 | * fixes Sourcify::NoMatchingProcError when if/unless/until/while modifier follows 30 | a trailing backslash (see issue#5) [#ngty] 31 | 32 | === 0.4.0 (Oct 15, 2010) 33 | 34 | * adds Proc#to_source(:strip_enclosure => ...) (& the Proc#to_sexp equivalent) to ease 35 | stripping of enclosing 'proc {|params| ... }', returning only the inner code body 36 | '...' [#ngty] 37 | * adds Proc#to_source(:attached_to => ..., :ignore_nested => ..., &body_matcher) (& the 38 | Proc#to_sexp equivalent) to narrow down code scanning, avoiding unnecessary 39 | Sourcify::MultipleMatchingProcsPerLineError, useful for libs that can anticipate 40 | how the proc should look like [#ngty] 41 | * adds support for running in MRI-1.9.2 [#ngty] 42 | * fixes '/' operator always treated as start of regexp [#ngty & #seamusabshere] 43 | 44 | === 0.3.0 (Sep 23, 2010) 45 | 46 | * Proc#to_source & friends now work in IRB as well [#ngty] 47 | 48 | === 0.2.3 (Sep 15, 2010) 49 | 50 | * since (static) code scanner doesn't run in 1.8.6, we enforce ParseTree mode 51 | for 1.8.6 [#ngty] 52 | 53 | === 0.2.2 (Sep 15, 2010) 54 | 55 | * fixed failure to run on MRI-1.8.6 [#ngty] 56 | 57 | === 0.2.1 (Sep 14, 2010) 58 | 59 | * introduced hack to ensure procs generated by Symbol#to_proc & Method#to_proc 60 | behaves exactly the same way under 1.8.*, 1.9.* & JRuby ~> always throwing 61 | CannotHandleCreatedOnTheFlyProcError [#ngty] 62 | * minor cleaning up of ragel scanner [#ngty] 63 | 64 | === 0.2.0 (Sep 10, 2010) 65 | 66 | * use home-baked ragel-based scanner for scanning for proc code [#ngty] 67 | * renamed Sourcify::LexerInternalError to Sourcify::ParserInternalError since 68 | we are not using any lexer anymore [#ngty] 69 | * introduces CannotParseEvalCodeError, CannotParseIrbCodeError & 70 | CannotHandleCreatedOnTheFlyProcError to handle procs that there is no way 71 | to extract code from [#ngty] 72 | * tested against well known projects (eg. spree & redmine) to show that it is 73 | indeed working [#ngty] 74 | 75 | === 0.1.2 (Aug 30, 2010) 76 | 77 | * introduced throwing of Sourcify::LexerInternalError when parser cannot handle 78 | incorrectly lexed code fragments [#ngty] 79 | * fixed bug in lexing keyword literals (represented as Symbol) [#ngty] 80 | 81 | === 0.1.1 (Aug 30, 2010) 82 | 83 | * fixed empty return for Proc#to_sexp after calling of Proc#to_source [#ngty] 84 | 85 | === 0.1.0 (Aug 28, 2010) 86 | 87 | * 1st gem release !! [#ngty] 88 | 89 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 NgTzeYang 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /lib/sourcify.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'ruby_parser' 3 | require 'sexp_processor' 4 | require 'ruby2ruby' 5 | require 'file/tail' 6 | 7 | begin 8 | require 'parse_tree' 9 | require 'parse_tree_extensions' 10 | rescue LoadError 11 | # ParseTree is now optional for all supported rubies :) 12 | end 13 | 14 | module Sourcify #:nodoc: 15 | 16 | IS_19x = RUBY_VERSION.include?('1.9.') 17 | 18 | HAS_RIPPER = 19 | begin 20 | require 'ripper' 21 | true 22 | rescue LoadError 23 | false 24 | end 25 | 26 | class << self 27 | 28 | def require_rb(*args) 29 | require root(*args) 30 | end 31 | 32 | def root(*args) 33 | @root ||= File.join(File.dirname(File.expand_path(__FILE__)), 'sourcify') 34 | File.join(@root, *args) 35 | end 36 | 37 | end 38 | end 39 | 40 | Sourcify.require_rb('patches') 41 | Sourcify.require_rb('errors') 42 | Sourcify.require_rb('version') 43 | Sourcify.require_rb('proc') 44 | Sourcify.require_rb('method') 45 | -------------------------------------------------------------------------------- /lib/sourcify/common/parser/converter.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Common 3 | class Parser #:nodoc:all 4 | class Converter 5 | class << self 6 | 7 | RUBY_PARSER = RubyParser.new 8 | RUBY_2_RUBY = Ruby2Ruby.new 9 | 10 | def to_sexp(code, file = nil) 11 | retried = false 12 | begin 13 | RUBY_PARSER.reset 14 | (retried ? RubyParser.new : RUBY_PARSER).parse(*[code, file].compact) 15 | rescue Racc::ParseError, SyntaxError 16 | return nil if retried 17 | retried = true; retry 18 | end 19 | end 20 | 21 | def to_code(sexp) 22 | RUBY_2_RUBY.process(Sexp.from_array(sexp.to_a)) 23 | end 24 | 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/sourcify/common/parser/raw_scanner/comment.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Common 3 | class Parser 4 | module RawScanner #:nodoc:all 5 | class Comment 6 | 7 | def <<(content) 8 | (@contents ||= []) << content 9 | end 10 | 11 | def to_s 12 | @contents.join 13 | end 14 | 15 | def closed? 16 | @contents[-1].split("\n")[-1].strip == '=end' 17 | end 18 | 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/sourcify/common/parser/raw_scanner/counter.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Common 3 | class Parser 4 | module RawScanner #:nodoc:all 5 | class Counter 6 | 7 | attr_reader :counts 8 | 9 | def initialize 10 | @counts = [0,0] 11 | end 12 | 13 | def started? 14 | @counts.any?(&:nonzero?) 15 | end 16 | 17 | def just_started? 18 | @counts.any?{|count| count == 1 } 19 | end 20 | 21 | def balanced? 22 | @counts.any?(&:zero?) 23 | end 24 | 25 | def decrement 26 | (0..1).each{|i| @counts[i] -= 1 unless @counts[i].zero? } 27 | end 28 | 29 | def increment(val = 1) 30 | if val.is_a?(Range) 31 | @counts[0] += val.first 32 | @counts[1] += val.last 33 | else 34 | (0..1).each{|i| @counts[i] += 1 } 35 | end 36 | end 37 | 38 | end 39 | 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/sourcify/common/parser/raw_scanner/dstring.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Common 3 | class Parser 4 | module RawScanner #:nodoc:all 5 | class DString < Struct.new(:tag, :encoding) 6 | 7 | # To suppress 'warning: Object#type is deprecated; use Object#class' when 8 | # evaluating string 9 | attr_reader :type 10 | 11 | def <<(content) 12 | (@contents ||= []) << content 13 | end 14 | 15 | def to_s 16 | @contents.join 17 | end 18 | 19 | def closed? 20 | evaluable? && parsable? 21 | end 22 | 23 | private 24 | 25 | CLOSING_TAGS = {'(' => ')', '[' => ']', '<' => '>', '{' => '}'} 26 | 27 | def evaluable? 28 | @contents.length >= 2 && 29 | @contents[-1][-1].chr == end_tag 30 | end 31 | 32 | def parsable? 33 | !!RubyParser.new.parse(safe_contents) 34 | rescue SyntaxError, Racc::ParseError 35 | false 36 | end 37 | 38 | def safe_contents 39 | # NOTE: %x & ` strings are dangerous to eval cos they execute shell commands, 40 | # thus we convert them to normal strings 1st 41 | to_s.gsub(/(%x)(\W|\_)/, '%Q\2').gsub(/.{0,2}(`)/) do |s| 42 | s =~ /^(%Q|%W|%r|%x|.?%|.?\\)/ ? s : s.sub(/`$/,'%Q`') 43 | end.force_encoding(encoding) 44 | end 45 | 46 | def start_tag 47 | @start_tag ||= tag[-1].chr 48 | end 49 | 50 | def end_tag 51 | @end_tag ||= (CLOSING_TAGS[start_tag] || start_tag) 52 | end 53 | 54 | end 55 | end 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/sourcify/common/parser/raw_scanner/heredoc.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Common 3 | class Parser 4 | module RawScanner #:nodoc:all 5 | class Heredoc < Struct.new(:tag, :indented, :encoding) 6 | 7 | def <<(content) 8 | (@contents ||= []) << content 9 | end 10 | 11 | def to_s 12 | @contents.join.force_encoding(encoding) 13 | end 14 | 15 | def closed?(sealer) 16 | return false unless sealer == "\n" 17 | parts = @contents[-1].split("\n") 18 | return true if parts[-1] == tag 19 | indented && parts[-1].sub(/^\s*(.*)$/,'\1') == tag 20 | end 21 | 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/sourcify/common/parser/source_code.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Common 3 | class Parser #:nodoc:all 4 | class SourceCode < Struct.new(:file, :line) 5 | 6 | def line 7 | super.pred 8 | end 9 | 10 | def to_s 11 | case file 12 | when /\(irb\)/, /\(irb\#\d+\)/ then from_irb_to_s 13 | when /\(pry\)/ then from_pry_to_s 14 | else from_file_to_s 15 | end 16 | end 17 | 18 | def from_file_to_s 19 | File.open(file, 'r') do |fh| 20 | fh.extend(File::Tail).forward(line) 21 | fh.readlines.join 22 | end 23 | end 24 | 25 | def from_irb_to_s 26 | # Really owe it to Florian Groß's solution @ http://rubyquiz.com/quiz38.html ... 27 | # anyway, note that we use *line.succ* instead of *line* here. 28 | IRB.CurrentContext.io.line(line.succ .. -1).join 29 | end 30 | 31 | def from_pry_to_s 32 | # NOTE: HACK to reliably construct the lines required, as: 33 | # * Pry.line_buffer always fail to show the last entry 34 | # * Pry.history deliberately skips duplicated consecutive lines, 35 | # yet it reliably shows the last 36 | [ 37 | Pry.line_buffer, 38 | Pry.history.to_a[-1] 39 | ].flatten[line.succ .. -1] * "" 40 | end 41 | 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/sourcify/common/ragel/common.rl: -------------------------------------------------------------------------------- 1 | %%{ 2 | machine common; 3 | include common_expressions 'expressions.rl'; 4 | include common_machines 'machines.rl'; 5 | 6 | -------------------------------------------------------------------------------- /lib/sourcify/common/ragel/expressions.rl: -------------------------------------------------------------------------------- 1 | %%{ 2 | machine common_expressions; 3 | 4 | kw_class = 'class'; 5 | kw_module = 'module'; 6 | kw_def = 'def'; 7 | kw_begin = 'begin'; 8 | kw_case = 'case'; 9 | kw_if = 'if'; 10 | kw_unless = 'unless'; 11 | kw_do = 'do'; 12 | kw_then = 'then'; 13 | kw_for = 'for'; 14 | kw_while = 'while'; 15 | kw_until = 'until'; 16 | kw_end = 'end'; 17 | 18 | vchar = alnum | '_'; 19 | const = upper . vchar* . ('::' . alpha . vchar*)*; 20 | var = (lower | '_') . vchar*; 21 | meth = (alpha | '_') . vchar*; 22 | symbol = ':' . (var | const); 23 | assoc = '=>'; 24 | assgn = '='; 25 | comma = ','; 26 | label = (var | const) . ':'; 27 | 28 | lparen = '('; 29 | rparen = ')'; 30 | lbrace = '{'; 31 | rbrace = '}'; 32 | smcolon = ';'; 33 | newline = '\n'; 34 | bslash = '\\' . newline; 35 | ospaces = space* -- newline; 36 | mspaces = space+ -- newline; 37 | 38 | }%% 39 | -------------------------------------------------------------------------------- /lib/sourcify/errors.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | class ParserInternalError < Exception; end 3 | class CannotParseEvalCodeError < Exception; end 4 | end 5 | -------------------------------------------------------------------------------- /lib/sourcify/method/methods.rb: -------------------------------------------------------------------------------- 1 | %w{to_source to_sexp to_raw_source}.each do |file| 2 | Sourcify.require_rb('method', 'methods', file) 3 | end 4 | -------------------------------------------------------------------------------- /lib/sourcify/method/methods/to_raw_source.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Method 3 | module Methods #:nodoc:all 4 | module ToRawSource 5 | def self.included(base) 6 | base.class_eval do 7 | 8 | Sourcify.require_rb('method', 'parser') 9 | 10 | if IS_PLATFORM_SUPPORTED 11 | 12 | def to_raw_source(opts = {}, &body_matcher) 13 | (@sourcified_parser ||= Parser.new(self)). 14 | raw_source(opts.merge(:body_matcher => body_matcher)) 15 | end 16 | 17 | else 18 | 19 | def to_raw_source(*args) 20 | raise PlatformNotSupportedError 21 | end 22 | 23 | end 24 | 25 | end 26 | end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/sourcify/method/methods/to_sexp.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Method 3 | module Methods #:nodoc:all 4 | module ToSexp 5 | def self.included(base) 6 | base.class_eval do 7 | 8 | Sourcify.require_rb('method', 'parser') 9 | 10 | if IS_PLATFORM_SUPPORTED 11 | 12 | def to_sexp(opts = {}, &body_matcher) 13 | (@sourcified_parser ||= Parser.new(self)). 14 | sexp(opts.merge(:body_matcher => body_matcher)) 15 | end 16 | 17 | else 18 | 19 | def to_sexp(*args) 20 | raise PlatformNotSupportedError 21 | end 22 | 23 | end 24 | 25 | end 26 | end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/sourcify/method/methods/to_source.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Method 3 | module Methods #:nodoc:all 4 | module ToSource 5 | def self.included(base) 6 | base.class_eval do 7 | 8 | Sourcify.require_rb('method', 'parser') 9 | 10 | if IS_PLATFORM_SUPPORTED 11 | 12 | def to_source(opts = {}, &body_matcher) 13 | (@sourcified_parser ||= Parser.new(self)). 14 | source(opts.merge(:body_matcher => body_matcher)) 15 | end 16 | 17 | else 18 | 19 | def to_source(*args) 20 | raise PlatformNotSupportedError 21 | end 22 | 23 | end 24 | 25 | end 26 | end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/sourcify/method/parser.rb: -------------------------------------------------------------------------------- 1 | %w{scanner source_code converter}.each do |file| 2 | Sourcify.require_rb('method', 'parser', file) 3 | end 4 | 5 | module Sourcify 6 | module Method 7 | class Parser #:nodoc:all 8 | 9 | class ProbablyDefinedByProc < Exception; end 10 | 11 | def initialize(_meth) 12 | @parameters, @name = _meth.parameters, _meth.name 13 | @source_code = SourceCode.new(*_meth.source_location) 14 | raise CannotFindSourceLocationError unless @source_code.file 15 | raise CannotParseEvalCodeError if @source_code.file == '(eval)' 16 | end 17 | 18 | def raw_source(opts) 19 | raw_source = extracted_source(opts)[0].strip 20 | opts[:strip_enclosure] ? strip_raw_enclosure(raw_source) : raw_source 21 | end 22 | 23 | def source(opts) 24 | (@sources ||= {})[opts.hash] ||= Converter.to_code(sexp(opts)) 25 | end 26 | 27 | def sexp(opts) 28 | (@sexps ||= {})[opts.hash] ||= ( 29 | extracted = extracted_source(opts)[1] 30 | raw_code = (("\n" * @source_code.line) + extracted).same_encoding_as(extracted) 31 | 32 | sexp = Converter.to_sexp(raw_code, @source_code.file) 33 | opts[:strip_enclosure] ? Sexp.from_array(sexp.to_a[-1]) : sexp 34 | ) 35 | end 36 | 37 | private 38 | 39 | def strip_raw_enclosure(source) 40 | inner = 41 | if @parameters.empty? 42 | '\s*' 43 | else 44 | @parameters.map do |param| 45 | if name = param[1] 46 | case param[0] 47 | when :req then name 48 | when :opt then "#{name}\s*=\s*.*?" 49 | when :rest then "\\*#{name}" 50 | end 51 | else 52 | '\(.*?\)' 53 | end 54 | end.join('\s*,\s*') 55 | end 56 | pattern = %r{^def\s+#{@name}(?:(?:\(\s*#{inner}\s*\))|(?:\s+#{inner}\s+))?(.*)end$}m 57 | source.sub(pattern, '\1').strip 58 | end 59 | 60 | def extracted_source(opts) 61 | begin 62 | extracted_source_from_method(opts) 63 | rescue ProbablyDefinedByProc 64 | pattern = /^proc\s*(\{|do)\s*(\|[^\|]*\|)?(.+)(\}|end)$/m 65 | extracted = extracted_source_from_proc(opts) 66 | matches = extracted.map{|s| s.match(pattern) } 67 | 68 | ( 69 | if @parameters.empty? 70 | matches.map{|match| %Q(def #{@name}\n#{match[3]}\nend) } 71 | else 72 | args = matches[0][2].sub(/^\|([^\|]+)\|$/, '\1') 73 | matches.map{|match| %Q(def #{@name}(#{args})\n#{match[3]}\nend) } 74 | end 75 | ).map{|s| s.same_encoding_as(extracted[0]) } 76 | end 77 | end 78 | 79 | def extracted_source_from_method(opts) 80 | Scanner.process(@source_code, opts) do |(raw, normalized)| 81 | begin 82 | Object.new.instance_eval("#{raw}; self".same_encoding_as(raw)). 83 | method(@name).parameters == @parameters 84 | rescue NameError 85 | false 86 | rescue Exception 87 | raise ParserInternalError 88 | end 89 | end 90 | end 91 | 92 | def extracted_source_from_proc(opts) 93 | Proc::Parser::Scanner.process(@source_code, opts) do |raw| 94 | begin 95 | Object.new.instance_eval(%( 96 | (class << self; self; end).class_eval do 97 | define_method(:#{@name}, &(#{raw})) 98 | end; self 99 | ).same_encoding_as(raw)).method(@name).parameters == @parameters 100 | rescue NameError 101 | false 102 | rescue Exception 103 | raise ParserInternalError 104 | end 105 | end 106 | end 107 | 108 | end 109 | end 110 | end 111 | -------------------------------------------------------------------------------- /lib/sourcify/method/parser/converter.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Method 3 | class Parser #:nodoc:all 4 | Sourcify.require_rb('common', 'parser', 'converter') 5 | Converter = Common::Parser::Converter 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/sourcify/method/parser/raw_scanner.rl: -------------------------------------------------------------------------------- 1 | Sourcify.require_rb('method', 'parser', 'raw_scanner_extensions') 2 | 3 | module Sourcify 4 | module Method 5 | class Parser 6 | module RawScanner #:nodoc:all 7 | 8 | %%{ 9 | 10 | machine scanner; 11 | include common 'common.rl'; 12 | 13 | ## MACHINE >> New statement 14 | new_statement := |* 15 | 16 | (kw_for | kw_while | kw_until) . ^vchar => { 17 | push(:kw_do_alias2, ts, te) 18 | increment_counter(0..1) 19 | fgoto main; 20 | }; 21 | 22 | ( 23 | ((kw_class | kw_module | kw_do | kw_begin | kw_case | kw_if | kw_unless) . ^vchar) | 24 | (kw_class . ospaces . '<<' . ospaces . ^(newline | smcolon)+) 25 | ) => { 26 | push(:kw_do_alias1, ts, te) 27 | increment_counter(1) 28 | fgoto main; 29 | }; 30 | 31 | ospaces => { push(:space, ts, te) }; 32 | any => { fhold; fgoto main; }; 33 | 34 | *|; 35 | 36 | 37 | ## MACHINE >> Main 38 | main := |* 39 | 40 | ## == Start/end of def..end block 41 | 42 | kw_def => { 43 | push(:kw_def, ts, te) 44 | increment_counter(1) 45 | fgoto new_statement; 46 | }; 47 | 48 | kw_end => { 49 | push(:kw_end, ts, te) 50 | decrement_counter() 51 | }; 52 | 53 | ## == Start/end of {...} block 54 | 55 | lbrace => { 56 | push(:lbrace, ts, te) 57 | }; 58 | 59 | rbrace => { 60 | push(:rbrace, ts, te) 61 | }; 62 | 63 | assoc => { 64 | push(:assoc, ts, te) 65 | }; 66 | 67 | label => { 68 | push_label(ts, te) 69 | }; 70 | 71 | ## == New statement 72 | 73 | newline => { 74 | push(:newline, ts, te) 75 | increment_lineno 76 | fgoto new_statement; 77 | }; 78 | 79 | smcolon | lparen | assgn | kw_then | comma => { 80 | push(:newline_alias, ts, te) 81 | fgoto new_statement; 82 | }; 83 | 84 | ## == Comment 85 | 86 | '#' => { 87 | fgoto per_line_comment; 88 | }; 89 | 90 | newline . '=begin' . ospaces . (ospaces . ^newline+)* . newline => { 91 | push_comment(ts, te) 92 | increment_lineno 93 | fgoto block_comment; 94 | }; 95 | 96 | ## == Strings 97 | 98 | ('<<' | '<<-') . ["']? . (const | var) . ["']? . newline => { 99 | push_heredoc(ts, te) 100 | increment_lineno 101 | fgoto heredoc; 102 | }; 103 | 104 | ('"' | "'" | '`' | '%') => { 105 | fhold; fgoto string; 106 | }; 107 | 108 | '/' => { 109 | if preceded_with?(:char, :digit, :var, :const, :symbol, :dstring, :sstring, ')', ']', '}') 110 | push(:op, ts, te) 111 | else 112 | fhold; fgoto string; 113 | end 114 | }; 115 | 116 | ## == Misc 117 | 118 | var => { push(:var, ts, te) }; 119 | bslash => { push(:bslash, ts, te) }; 120 | const => { push(:const, ts, te) }; 121 | symbol => { push(:symbol, ts, te) }; 122 | mspaces => { push(:space, ts, te) }; 123 | [0-9] => { push(:digit, ts, te) }; 124 | lower => { push(:char, ts, te) }; 125 | any => { push(:any, ts, te) }; 126 | 127 | *|; 128 | 129 | }%% 130 | %% write data; 131 | 132 | extend Extensions 133 | 134 | def self.execute! 135 | data = @data 136 | eof = data.length 137 | %% write init; 138 | %% write exec; 139 | end 140 | 141 | end 142 | end 143 | end 144 | end 145 | -------------------------------------------------------------------------------- /lib/sourcify/method/parser/raw_scanner_extensions.rb: -------------------------------------------------------------------------------- 1 | Sourcify.require_rb('common', 'parser', 'raw_scanner', 'extensions') 2 | 3 | module Sourcify 4 | module Method 5 | class Parser 6 | module RawScanner #:nodoc:all 7 | module Extensions 8 | 9 | include Common::Parser::RawScanner::Extensions 10 | Counter = Common::Parser::RawScanner::Counter 11 | 12 | def increment_lineno 13 | stop_if_probably_defined_by_proc 14 | super 15 | end 16 | 17 | def stop_if_probably_defined_by_proc 18 | raise ProbablyDefinedByProc if @lineno == 1 && @results.empty? && !@counter.started? 19 | end 20 | 21 | def increment_counter(count = 1) 22 | unless @counter.started? 23 | return if (@rejecting_block = codified_tokens !~ @start_pattern) 24 | offset_attributes 25 | end 26 | @counter.increment(count) 27 | end 28 | 29 | def decrement_counter 30 | @counter.decrement 31 | construct_result_code if @counter.balanced? 32 | end 33 | 34 | def construct_result_code 35 | codes = [false, true].map do |fix_heredoc| 36 | codified_tokens(fix_heredoc).force_encoding(@encoding) 37 | end 38 | 39 | begin 40 | if valid?(codes[1]) && @body_matcher.call(codes[0]) 41 | # NOTE: Need to fix singleton method to avoid errors (eg. undefined object) 42 | # downstream 43 | @results << codes.map do |s| 44 | s.sub(%r{^(def\s+)(?:[^\.]+\.)?(#{@name}.*end)$}m, '\1\2') 45 | end 46 | raise Escape if @stop_on_newline or @lineno != 1 47 | reset_attributes 48 | end 49 | rescue Exception 50 | raise if $!.is_a?(Escape) 51 | end 52 | end 53 | 54 | def reset_attributes 55 | @counter = Counter.new 56 | super 57 | end 58 | 59 | def valid?(*args) 60 | # TODO: shouldn't need this check, there seems to be a bug w raw_scanner.rl. 61 | args[0].start_with?('def') && super 62 | end 63 | 64 | end 65 | end 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /lib/sourcify/method/parser/scanner.rb: -------------------------------------------------------------------------------- 1 | Sourcify.require_rb('method', 'parser', 'raw_scanner') 2 | 3 | module Sourcify 4 | module Method 5 | class Parser #:nodoc:all 6 | class Scanner 7 | class << self 8 | 9 | def process(source_code, opts, &matcher) 10 | results = rscan(source_code.to_s, { 11 | :start_pattern => scan_pattern_hint(opts[:attached_to]), 12 | :body_matcher => opts[:body_matcher], 13 | :ignore_nested => opts[:ignore_nested], 14 | :stop_on_newline => false, 15 | }).select{|(raw, normalized)| matcher.call(raw) } 16 | 17 | case results.size 18 | when 0 then raise NoMatchingMethodError 19 | when 1 then results[0] 20 | else raise MultipleMatchingMethodsPerLineError 21 | end 22 | end 23 | 24 | def scan_pattern_hint(val) 25 | case val 26 | when Regexp then val 27 | when String, Symbol then /^(?:.*?\W|)#{val}(?:\W)/ 28 | when nil then /.*/ 29 | else raise TypeError 30 | end 31 | end 32 | 33 | def rscan(str, opts) 34 | results = RawScanner.process(str, opts) || [] 35 | inner_opts = opts.merge(:stop_on_newline => true) 36 | return results if opts[:ignore_nested] 37 | results.map do |outer| 38 | [ 39 | outer, 40 | *rscan( 41 | outer[0].sub(/^def(.*)end$/,'\1').sub(/^(?:.*?)(def.*)$/,'\1'), 42 | inner_opts 43 | ) 44 | ] 45 | end.flatten(1) 46 | end 47 | 48 | end 49 | end 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /lib/sourcify/method/parser/source_code.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Method 3 | class Parser #:nodoc:all 4 | Sourcify.require_rb('common', 'parser', 'source_code') 5 | SourceCode = Common::Parser::SourceCode 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/sourcify/patches.rb: -------------------------------------------------------------------------------- 1 | if RUBY_VERSION.include?('1.8.6') 2 | 3 | unless 1.respond_to?(:pred) 4 | class Integer 5 | def pred 6 | self - 1 7 | end 8 | end 9 | end 10 | 11 | unless :a.respond_to?(:to_proc) 12 | class Symbol 13 | def to_proc 14 | Proc.new{|*args| args.shift.__send__(self, *args)} 15 | end 16 | end 17 | end 18 | 19 | end 20 | 21 | unless binding.respond_to?(:has_local_variable?) 22 | class Binding 23 | def has_local_variable?(name) 24 | check_str = "local_variables.include?(#{name})" 25 | self.eval(check_str) rescue eval(check_str, self) 26 | end 27 | end 28 | end 29 | 30 | # New way of adding new functionalities 31 | module Sourcify 32 | module Patches 33 | 34 | module String 35 | if ''.respond_to?(:force_encoding) 36 | 37 | def same_encoding_as(other) 38 | force_encoding(other.encoding) 39 | end 40 | 41 | else 42 | 43 | def same_encoding_as(other) 44 | self 45 | end 46 | 47 | def encoding 48 | nil 49 | end 50 | 51 | def force_encoding(dummy) 52 | self 53 | end 54 | 55 | end 56 | end 57 | 58 | ::String.class_eval do 59 | include Sourcify::Patches::String 60 | end 61 | 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /lib/sourcify/proc/methods.rb: -------------------------------------------------------------------------------- 1 | %w{source_location to_source to_sexp to_raw_source}.each do |file| 2 | Sourcify.require_rb('proc', 'methods', file) 3 | end 4 | -------------------------------------------------------------------------------- /lib/sourcify/proc/methods/source_location.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Proc 3 | module Methods #:nodoc:all 4 | module SourceLocation 5 | def self.included(base) 6 | base.class_eval do 7 | 8 | # Case (1): the family of 1.9.* behaves slightly differently for created on 9 | # the fly proc, eg. 1.9.2 does yield meaningful Proc#source_location for procs 10 | # created from Method#to_proc. Since it is not possible to derive the same 11 | # behaviour for other rubies, we stick to the less performant behaviour. 12 | if lambda{}.respond_to?(:source_location) 13 | 14 | alias_method :__pre_sourcified_source_location, :source_location 15 | 16 | def source_location(get_original = true) 17 | if get_original 18 | __pre_sourcified_source_location 19 | elsif !@created_on_the_fly 20 | __pre_sourcified_source_location 21 | end 22 | end 23 | 24 | # Case (2): okko, we are on rubies that don't support Proc#source_location .. 25 | else 26 | 27 | def source_location(get_original = true) 28 | unless @created_on_the_fly 29 | @source_location ||= ( 30 | file, line = /^#$/.match(inspect)[1..2] 31 | [file, line.to_i] 32 | ) 33 | end 34 | end 35 | 36 | end 37 | 38 | # HACK to make it real easy to determine if a proc is created on the fly 39 | # (eg. Method#to_proc & Symbol#to_proc). 40 | 41 | attr_writer :created_on_the_fly 42 | 43 | [::Method, ::Symbol].each do |klass| 44 | begin 45 | klass.class_eval do 46 | alias_method :__pre_sourcified_to_proc, :to_proc 47 | def to_proc 48 | (_proc = __pre_sourcified_to_proc).created_on_the_fly = true 49 | _proc 50 | end 51 | end 52 | rescue NameError 53 | end 54 | end 55 | 56 | end 57 | end 58 | end 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/sourcify/proc/methods/to_raw_source.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Proc 3 | module Methods #:nodoc:all 4 | module ToRawSource 5 | def self.included(base) 6 | base.class_eval do 7 | 8 | Sourcify.require_rb('proc', 'parser') 9 | 10 | def to_raw_source(opts = {}, &body_matcher) 11 | (@sourcified_parser ||= Parser.new(self)). 12 | raw_source(opts.merge(:body_matcher => body_matcher)) 13 | end 14 | 15 | end 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/sourcify/proc/methods/to_sexp.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Proc 3 | module Methods #:nodoc:all 4 | module ToSexp 5 | def self.included(base) 6 | base.class_eval do 7 | 8 | ref_proc = lambda {} 9 | 10 | # Case 1: we already have Proc#to_sexp (eg. provided by ParseTree) available, 11 | # we override it to ensure it handles the extra args .. 12 | if ref_proc.respond_to?(:to_sexp) 13 | 14 | alias_method :__pre_sourcified_to_sexp, :to_sexp 15 | 16 | def to_sexp(opts = {}, &body_matcher) 17 | sexp, flag = __pre_sourcified_to_sexp, opts[:strip_enclosure] 18 | Marshal.load(Marshal.dump( # need a deep copy cos the caller may reset the sexp 19 | (@sourcified_sexps ||= {})[flag] ||= 20 | flag ? Sexp.from_array(sexp.to_a.last) : sexp 21 | )) 22 | end 23 | 24 | # Case 2: okko, we have to implement our own Proc#to_sexp ... 25 | else 26 | 27 | Sourcify.require_rb('proc', 'parser') 28 | 29 | def to_sexp(opts = {}, &body_matcher) 30 | (@sourcified_parser ||= Parser.new(self)). 31 | sexp(opts.merge(:body_matcher => body_matcher)) 32 | end 33 | 34 | end 35 | end 36 | end 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/sourcify/proc/methods/to_source.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Proc 3 | module Methods #:nodoc:all 4 | module ToSource 5 | def self.included(base) 6 | base.class_eval do 7 | 8 | ref_proc = lambda {} 9 | 10 | # Case 1: the current ruby already implements Proc#to_source, 11 | # we override it to ensure it handles the extra args .. 12 | if ref_proc.respond_to?(:to_source) 13 | 14 | alias_method :__pre_sourcified_to_source, :to_source 15 | 16 | def to_source(opts = {}, &body_matcher) 17 | flag = opts[:strip_enclosure] 18 | (@sourcified_sources ||= {})[flag] ||= 19 | flag ? Ruby2Ruby.new.process(to_sexp(opts, &body_matcher)) : __pre_sourcified_to_source 20 | end 21 | 22 | # Case 2: we have Proc#to_ruby (eg. provided by ParseTree) available, 23 | # we have a wrapper round it to ensure it handles the extra args .. 24 | elsif ref_proc.respond_to?(:to_ruby) 25 | 26 | def to_source(opts = {}, &body_matcher) 27 | flag = opts[:strip_enclosure] 28 | (@sourcified_sources ||= {})[flag] ||= 29 | flag ? Ruby2Ruby.new.process(to_sexp(opts, &body_matcher)) : to_ruby 30 | end 31 | 32 | # Case 3: okko, we have to implement our own Proc#to_source ... 33 | else 34 | 35 | Sourcify.require_rb('proc', 'parser') 36 | 37 | def to_source(opts = {}, &body_matcher) 38 | (@sourcified_parser ||= Parser.new(self)). 39 | source(opts.merge(:body_matcher => body_matcher)) 40 | end 41 | 42 | end 43 | end 44 | end 45 | end 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /lib/sourcify/proc/parser.rb: -------------------------------------------------------------------------------- 1 | %w{normalizer scanner source_code converter}.each do |file| 2 | Sourcify.require_rb('proc', 'parser', file) 3 | end 4 | 5 | module Sourcify 6 | module Proc 7 | class Parser #:nodoc:all 8 | 9 | def initialize(_proc) 10 | @arity, @source_code = _proc.arity, SourceCode.new(*_proc.source_location(false)) 11 | raise CannotHandleCreatedOnTheFlyProcError unless @source_code.file 12 | raise CannotParseEvalCodeError if @source_code.file == '(eval)' 13 | @binding = _proc.binding # this must come after the above check 14 | end 15 | 16 | def source(opts) 17 | (@sources ||= {})[opts.hash] ||= Converter.to_code(sexp(opts)) 18 | end 19 | 20 | def sexp(opts) 21 | (@sexps ||= {})[opts.hash] ||= ( 22 | extracted = extracted_source(opts)[1] 23 | raw_code = (("\n" * @source_code.line) + extracted).same_encoding_as(extracted) 24 | 25 | raw_sexp = Converter.to_sexp(raw_code, @source_code.file) 26 | sexp = Normalizer.process(raw_sexp, @binding) 27 | opts[:strip_enclosure] ? Sexp.from_array(sexp.to_a.last) : sexp 28 | ) 29 | end 30 | 31 | def raw_source(opts) 32 | raw_code = extracted_source(opts)[0].strip 33 | opts[:strip_enclosure] ? 34 | raw_code.sub(/^proc\s*(\{|do)\s*(\|[^\|]+\|)?(.*)(\}|end)$/m, '\3').strip : raw_code 35 | end 36 | 37 | private 38 | 39 | def extracted_source(opts) 40 | Scanner.process(@source_code, opts) do |(raw, normalized)| 41 | begin 42 | eval(raw).arity == @arity 43 | rescue Exception 44 | raise ParserInternalError 45 | end 46 | end 47 | end 48 | 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/sourcify/proc/parser/converter.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Proc 3 | class Parser #:nodoc:all 4 | Sourcify.require_rb('common', 'parser', 'converter') 5 | Converter = Common::Parser::Converter 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/sourcify/proc/parser/normalizer.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Proc 3 | class Parser #:nodoc:all 4 | class Normalizer 5 | class << self 6 | 7 | def process(sexp, binding) 8 | @binding = binding 9 | Sexp.from_array(fix_no_arg_method_calls(sexp.to_a)) 10 | end 11 | 12 | def fix_no_arg_method_calls(array) 13 | return array if [:class, :sclass, :defn, :module].include?(array[0]) 14 | array.map do |e| 15 | if e.is_a?(Array) 16 | no_arg_method_call?(e) or fix_no_arg_method_calls(e) 17 | else 18 | e 19 | end 20 | end 21 | end 22 | 23 | def no_arg_method_call?(e) 24 | if like_no_arg_method_call?(e) 25 | bounded_var?(var = e[2]) ? [:lvar, var] : e 26 | end 27 | end 28 | 29 | def like_no_arg_method_call?(e) 30 | e.size == 4 && e[0..1] == [:call, nil] && 31 | e[3] == [:arglist] && (var = e[2]).is_a?(Symbol) 32 | end 33 | 34 | def bounded_var?(var) 35 | lvar = (@q ||= (IS_19x ? ":%s" : "'%s'")) % var 36 | @binding.has_local_variable?(lvar) 37 | end 38 | 39 | end 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/sourcify/proc/parser/raw_scanner.rl: -------------------------------------------------------------------------------- 1 | Sourcify.require_rb('proc', 'parser', 'raw_scanner_extensions') 2 | 3 | module Sourcify 4 | module Proc 5 | class Parser 6 | module RawScanner #:nodoc:all 7 | 8 | %%{ 9 | 10 | machine scanner; 11 | include common 'common.rl'; 12 | 13 | 14 | ## MACHINE >> New statement 15 | new_statement := |* 16 | 17 | (kw_for | kw_while | kw_until) . ^vchar => { 18 | push(:kw_do_alias2, ts, te) 19 | increment_counter(:do_end, 0..1) 20 | fgoto main; 21 | }; 22 | 23 | ( 24 | ((kw_class | kw_module | kw_def | kw_begin | kw_case | kw_if | kw_unless) . ^vchar) | 25 | (kw_class . ospaces . '<<' . ospaces . ^newline+) 26 | ) => { 27 | push(:kw_do_alias1, ts, te) 28 | increment_counter(:do_end, 1) 29 | fgoto main; 30 | }; 31 | 32 | ospaces => { push(:space, ts, te) }; 33 | any => { fhold; fgoto main; }; 34 | 35 | *|; 36 | 37 | 38 | ## MACHINE >> Main 39 | main := |* 40 | 41 | ## == Start/end of do..end block 42 | 43 | kw_do => { 44 | push(:kw_do, ts, te) 45 | increment_counter(:do_end) 46 | fgoto new_statement; 47 | }; 48 | 49 | kw_end => { 50 | push(:kw_end, ts, te) 51 | decrement_counter(:do_end) 52 | }; 53 | 54 | ## == Start/end of {...} block 55 | 56 | lbrace => { 57 | push(:lbrace, ts, te) 58 | increment_counter(:brace) 59 | }; 60 | 61 | rbrace => { 62 | push(:rbrace, ts, te) 63 | decrement_counter(:brace) 64 | }; 65 | 66 | assoc => { 67 | push(:assoc, ts, te) 68 | fix_counter_false_start(:brace) 69 | }; 70 | 71 | label => { 72 | push_label(ts, te) 73 | fix_counter_false_start(:brace) 74 | }; 75 | 76 | ## == New statement 77 | 78 | newline => { 79 | push(:newline, ts, te) 80 | increment_lineno 81 | fgoto new_statement; 82 | }; 83 | 84 | smcolon | lparen | assgn | kw_then | comma => { 85 | push(:newline_alias, ts, te) 86 | fgoto new_statement; 87 | }; 88 | 89 | ## == Comment 90 | 91 | '#' => { 92 | fgoto per_line_comment; 93 | }; 94 | 95 | newline . '=begin' . ospaces . (ospaces . ^newline+)* . newline => { 96 | push_comment(ts, te) 97 | increment_lineno 98 | fgoto block_comment; 99 | }; 100 | 101 | ## == Strings 102 | 103 | ('<<' | '<<-') . ["']? . (const | var) . ["']? . newline => { 104 | push_heredoc(ts, te) 105 | increment_lineno 106 | fgoto heredoc; 107 | }; 108 | 109 | ('"' | "'" | '`' | '%') => { 110 | fhold; fgoto string; 111 | }; 112 | 113 | '/' => { 114 | if preceded_with?(:char, :digit, :var, :const, :symbol, :dstring, :sstring, ')', ']', '}') 115 | push(:op, ts, te) 116 | else 117 | fhold; fgoto string; 118 | end 119 | }; 120 | 121 | ## == Misc 122 | 123 | var => { push(:var, ts, te) }; 124 | bslash => { push(:bslash, ts, te) }; 125 | const => { push(:const, ts, te) }; 126 | symbol => { push(:symbol, ts, te) }; 127 | mspaces => { push(:space, ts, te) }; 128 | [0-9] => { push(:digit, ts, te) }; 129 | lower => { push(:char, ts, te) }; 130 | any => { push(:any, ts, te) }; 131 | 132 | *|; 133 | 134 | }%% 135 | %% write data; 136 | 137 | extend Extensions 138 | 139 | def self.execute! 140 | data = @data 141 | eof = data.length 142 | %% write init; 143 | %% write exec; 144 | end 145 | 146 | end 147 | end 148 | end 149 | end 150 | -------------------------------------------------------------------------------- /lib/sourcify/proc/parser/raw_scanner_extensions.rb: -------------------------------------------------------------------------------- 1 | Sourcify.require_rb('common', 'parser', 'raw_scanner', 'extensions') 2 | 3 | module Sourcify 4 | module Proc 5 | class Parser 6 | module RawScanner #:nodoc:all 7 | module Extensions 8 | 9 | include Common::Parser::RawScanner::Extensions 10 | class DoEndBlockCounter < Common::Parser::RawScanner::Counter; end 11 | class BraceBlockCounter < Common::Parser::RawScanner::Counter; end 12 | 13 | def fix_counter_false_start(key) 14 | return unless this_counter(key).just_started? 15 | return unless really_false_started? 16 | reset_attributes 17 | @tokens, @false_start_backup = @false_start_backup.dup, nil if @false_start_backup 18 | end 19 | 20 | def increment_counter(key, count = 1) 21 | return if other_counter(key).started? 22 | unless (counter = this_counter(key)).started? 23 | return if (@rejecting_block = codified_tokens !~ @start_pattern) 24 | @false_start_backup = @tokens.dup if key == :brace 25 | offset_attributes 26 | end 27 | counter.increment(count) 28 | end 29 | 30 | def decrement_counter(key) 31 | return unless (counter = this_counter(key)).started? 32 | counter.decrement 33 | construct_result_code if counter.balanced? 34 | end 35 | 36 | def other_counter(type) 37 | {:do_end => @brace_counter, :brace => @do_end_counter}[type] 38 | end 39 | 40 | def this_counter(type) 41 | {:brace => @brace_counter, :do_end => @do_end_counter}[type] 42 | end 43 | 44 | def construct_result_code 45 | codes = [false, true].map do |fix_heredoc| 46 | %Q(proc #{codified_tokens(fix_heredoc)}).force_encoding(@encoding) 47 | end 48 | 49 | begin 50 | if valid?(codes[1]) && @body_matcher.call(codes[0]) 51 | @results << codes 52 | raise Escape if @stop_on_newline or @lineno != 1 53 | reset_attributes 54 | end 55 | rescue Exception 56 | raise if $!.is_a?(Escape) 57 | end 58 | end 59 | 60 | def really_false_started? 61 | valid?(%Q(#{codified_tokens(true)} 1}), :hash) 62 | end 63 | 64 | def reset_attributes 65 | @do_end_counter = DoEndBlockCounter.new 66 | @brace_counter = BraceBlockCounter.new 67 | super 68 | end 69 | 70 | end 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/sourcify/proc/parser/scanner.rb: -------------------------------------------------------------------------------- 1 | Sourcify.require_rb('proc', 'parser', 'raw_scanner') 2 | 3 | module Sourcify 4 | module Proc 5 | class Parser #:nodoc:all 6 | class Scanner 7 | class << self 8 | 9 | def process(source_code, opts, &matcher) 10 | results = rscan(source_code.to_s, { 11 | :start_pattern => scan_pattern_hint(opts[:attached_to]), 12 | :body_matcher => opts[:body_matcher], 13 | :ignore_nested => opts[:ignore_nested], 14 | :stop_on_newline => false, 15 | }).select{|(raw, normalized)| matcher.call(raw) } 16 | 17 | case results.size 18 | when 0 then raise NoMatchingProcError 19 | when 1 then results[0] 20 | else raise MultipleMatchingProcsPerLineError 21 | end 22 | end 23 | 24 | def scan_pattern_hint(val) 25 | case val 26 | when Regexp then val 27 | when String, Symbol then /^(?:.*?\W|)#{val}(?:\W)/ 28 | when nil then /.*/ 29 | else raise TypeError 30 | end 31 | end 32 | 33 | def rscan(str, opts) 34 | results = RawScanner.process(str, opts) || [] 35 | inner_opts = opts.merge(:stop_on_newline => true) 36 | return results if opts[:ignore_nested] 37 | results.map do |outer| 38 | [ 39 | outer, 40 | *rscan(outer[1].sub(/^proc\s*(do|\{)/,''), inner_opts) 41 | ] 42 | end.flatten(1) 43 | end 44 | 45 | end 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/sourcify/proc/parser/source_code.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | module Proc 3 | class Parser #:nodoc:all 4 | Sourcify.require_rb('common', 'parser', 'source_code') 5 | SourceCode = Common::Parser::SourceCode 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/sourcify/version.rb: -------------------------------------------------------------------------------- 1 | module Sourcify 2 | VERSION = "0.6.0.rc4" 3 | end 4 | -------------------------------------------------------------------------------- /sourcify.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "sourcify/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "sourcify" 7 | s.version = Sourcify::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ["NgTzeYang"] 10 | s.email = ["ngty77@gmail.com"] 11 | s.homepage = "http://github.com/ngty/sourcify" 12 | s.summary = %q{Workarounds before ruby-core officially supports Proc#to_source (& friends)} 13 | s.description = %q{} 14 | 15 | s.add_dependency 'ruby2ruby', '~> 1.3.1' 16 | s.add_dependency 'sexp_processor', '~> 3.2.0' 17 | s.add_dependency 'ruby_parser', '~> 2.3.1' 18 | s.add_dependency 'file-tail', '~> 1.0.10' 19 | 20 | s.add_development_dependency 'bacon' 21 | s.add_development_dependency 'pry' 22 | 23 | # ParseTree (better performance + dynamic goodness, but not supported on java & 1.9.*), 24 | # optional for any 1.8.*. 25 | #s.add_dependency "ParseTree", ">= 3.0.6" 26 | 27 | s.extra_rdoc_files = ["README.rdoc"] 28 | s.files = `git ls-files`.split("\n") 29 | s.test_files = `git ls-files -- spec/*`.split("\n") 30 | s.require_paths = ["lib"] 31 | end 32 | -------------------------------------------------------------------------------- /spec/dump_object_space_procs.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.dirname(File.expand_path(__FILE__)), '..', 'lib', 'sourcify') 2 | require 'benchmark' 3 | require 'pp' 4 | 5 | if RUBY_PLATFORM =~ /java/i 6 | require 'jruby' 7 | JRuby.objectspace = true 8 | reload! rescue nil 9 | end 10 | 11 | DUMPED_OBJECT_SPACE_PROCS = {:max => nil, :done => 0} 12 | DUMP_OBJECT_SPACE_PROCS_ERRORS = [] 13 | class STOP_DUMPING_OBJECT_SPACE_PROCS < Exception; end 14 | 15 | def dump_object_space_procs(debug = false) 16 | # Determine working dir 17 | name = [ 18 | RUBY_DESCRIPTION =~ /enterprise/i ? 'ree' : (RUBY_PLATFORM =~ /java/i ? 'jruby' : 'mri'), 19 | RUBY_VERSION, 20 | Object.const_defined?(:ParseTree) ? 'parsetree' : nil 21 | ].compact.join('~') 22 | dump_dir = File.join(File.dirname(File.expand_path(__FILE__)), '..', 'tmp', name) 23 | Dir.mkdir(dump_dir) unless File.exists?(dump_dir) 24 | 25 | puts '', 26 | '== NOTE: dump files can be found at %s' % dump_dir 27 | 28 | # Core processing 29 | ObjectSpace.each_object(Proc).to_a.select{|o| o.source_location }. 30 | group_by{|o| o.source_location[0] }.each do |ofile, objs| 31 | nfile = File.join(dump_dir, ofile.gsub('/','~')) 32 | File.open(nfile,'w') do |f| 33 | objs.sort_by{|o| o.source_location[1] }.map do |o| 34 | DUMPED_OBJECT_SPACE_PROCS[:done] += 1 35 | begin 36 | data = { 37 | :location => o.source_location, 38 | :sexp => o.to_sexp, 39 | :source => o.to_source 40 | } 41 | f.puts(data.pretty_inspect) 42 | print '.' 43 | rescue Exception 44 | data = { 45 | :location => o.source_location, 46 | :error => $!.inspect 47 | } 48 | DUMP_OBJECT_SPACE_PROCS_ERRORS << data 49 | f.puts(data.pretty_inspect) 50 | pp(data) if debug 51 | print 'x' 52 | ensure 53 | raise STOP_DUMPING_OBJECT_SPACE_PROCS \ 54 | if DUMPED_OBJECT_SPACE_PROCS.values.uniq.size == 1 55 | end 56 | end 57 | end 58 | end 59 | end 60 | 61 | # Dumping in action 62 | figures = Benchmark.measure do 63 | begin 64 | dump_object_space_procs 65 | rescue STOP_DUMPING_OBJECT_SPACE_PROCS 66 | end 67 | end 68 | 69 | # Printout the failures/passes 70 | unless DUMP_OBJECT_SPACE_PROCS_ERRORS.empty? 71 | puts '', '== OOPS, we have some erorrs :(' 72 | DUMP_OBJECT_SPACE_PROCS_ERRORS.each_with_index do |e, i| 73 | print "#{i}). %s" % e.pretty_inspect 74 | end 75 | else 76 | puts '', '== YEAH, no errors :)' 77 | end 78 | 79 | # Printout the benchmark results 80 | puts '', 81 | '== Benchmark results for processing %s procs:' % DUMPED_OBJECT_SPACE_PROCS[:done], 82 | figures.to_s, '' 83 | 84 | # __END__ 85 | -------------------------------------------------------------------------------- /spec/method/encoding_from_def_end_block_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 3 | 4 | describe "Encoding (from def..end block)" do 5 | next unless Sourcify::IS_19x 6 | 7 | should "handle body as UTF-8 string" do 8 | def m1; "こんにちは"; end 9 | method(:m1).should.be having_sexp( 10 | s(:defn, :m1, s(:args), s(:scope, s(:block, s(:str, "こんにちは")))) 11 | ) 12 | end 13 | 14 | should "handle body with unicode regexp" do 15 | # NOTE: This specifically addresses https://github.com/ngty/sourcify/issues/15 16 | def m2; /\p{Lu}/ ; end 17 | method(:m2).should.be having_sexp( 18 | s(:defn, :m2, s(:args), s(:scope, s(:block, s(:lit, /\p{Lu}/)))) 19 | ) 20 | end 21 | 22 | should "handle body with UTF-8 heredoc" do 23 | def m3 24 | <<-EOL 25 | こんにちは 26 | EOL 27 | end 28 | method(:m3).should.be having_sexp( 29 | s(:defn, :m3, s(:args), s(:scope, s(:block, s(:str, " こんにちは\n")))) 30 | ) 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /spec/method/encoding_from_define_method_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 3 | 4 | describe "Encoding (from define_method)" do 5 | next unless Sourcify::IS_19x 6 | 7 | before { @thing = Object.new } 8 | 9 | should "handle body as UTF-8 string" do 10 | b = lambda { "こんにちは" } 11 | @thing.class.send(:define_method, :m1, &b) 12 | @thing.method(:m1).should.be having_sexp( 13 | s(:defn, :m1, s(:args), s(:scope, s(:block, s(:str, "こんにちは")))) 14 | ) 15 | end 16 | 17 | should "handle body with unicode regexp" do 18 | # NOTE: This specifically addresses https://github.com/ngty/sourcify/issues/15 19 | b = lambda { /\p{Lu}/ } 20 | @thing.class.send(:define_method, :m2, &b) 21 | @thing.method(:m2).should.be having_sexp( 22 | s(:defn, :m2, s(:args), s(:scope, s(:block, s(:lit, /\p{Lu}/)))) 23 | ) 24 | end 25 | 26 | should "handle body with UTF-8 heredoc" do 27 | b = lambda do 28 | <<-EOL 29 | こんにちは 30 | EOL 31 | end 32 | @thing.class.send(:define_method, :m3, &b) 33 | @thing.method(:m3).should.be having_sexp( 34 | s(:defn, :m3, s(:args), s(:scope, s(:block, s(:str, " こんにちは\n")))) 35 | ) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/method/others_from_def_end_block_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Misc (from def..end block)" do 4 | 5 | should 'handle accessing #to_sexp after #to_source' do 6 | def m1; x; end 7 | (m = method(:m1)).to_source 8 | m.should.be having_sexp( 9 | s(:defn, :m1, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 10 | ) 11 | end 12 | 13 | should 'handle accessing #to_source after #to_sexp' do 14 | def m2; x; end 15 | (m = method(:m2)).to_sexp 16 | m.should.be having_source(%( 17 | def m2; x; end 18 | )) 19 | end 20 | 21 | should "handle body with '/' char" do 22 | def m3; x/2; end 23 | method(:m3).should.be having_source(%( 24 | def m3; x/2; end 25 | )) 26 | end 27 | 28 | should "handle lexer bug in missing trailing chars after '=>' operator" do 29 | # This example addresses bug @ http://redmine.ruby-lang.org/issues/show/3765 30 | { 31 | __LINE__ => (def m4; x; end; method(:m4)) 32 | }.values.last.should.be having_source(%( 33 | def m4; x; end 34 | )) 35 | end 36 | 37 | should 'raise Sourcify::CannotFindSourceLocationError when Method#source_location is nil' do 38 | lambda { 1.method(:to_s).to_source }.should. 39 | raise(Sourcify::CannotFindSourceLocationError) 40 | end 41 | 42 | unless has_parsetree? 43 | should "raise Sourcify::CannotParseEvalCodeError when method is created from eval" do 44 | lambda { eval("def m5; x; end; method(:m5)").to_source }.should. 45 | raise(Sourcify::CannotParseEvalCodeError) 46 | end 47 | end 48 | 49 | end 50 | -------------------------------------------------------------------------------- /spec/method/others_from_define_method_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 3 | 4 | describe "Misc (from define_method)" do 5 | 6 | before { @thing = Object.new } 7 | 8 | should 'handle accessing #to_sexp after #to_source' do 9 | blk = lambda { x } 10 | @thing.class.send(:define_method, :m1, &blk) 11 | (m = @thing.method(:m1)).to_source 12 | m.should.be having_sexp( 13 | s(:defn, :m1, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 14 | ) 15 | end 16 | 17 | should 'handle accessing #to_source after #to_sexp' do 18 | blk = lambda { x } 19 | @thing.class.send(:define_method, :m2, &blk) 20 | (m = @thing.method(:m2)).to_sexp 21 | m.should.be having_source(%( 22 | def m2; x; end 23 | )) 24 | end 25 | 26 | should "handle body with '/' char" do 27 | blk = lambda { x / 2 } 28 | @thing.class.send(:define_method, :m3, &blk) 29 | @thing.method(:m3).should.be having_source(%( 30 | def m3; x / 2; end 31 | )) 32 | end 33 | 34 | should "handle lexer bug in missing trailing chars after '=>' operator" do 35 | # This example addresses bug @ http://redmine.ruby-lang.org/issues/show/3765 36 | hash = { 37 | :x => lambda { x } 38 | } 39 | @thing.class.send(:define_method, :m4, &(hash[:x])) 40 | @thing.method(:m4).should.be having_source(%( 41 | def m4; x; end 42 | )) 43 | end 44 | 45 | should "handle lexer bug in missing trailing chars after '=>' operator" do 46 | # This example addresses bug @ http://redmine.ruby-lang.org/issues/show/3765 47 | hash = { 48 | :blk => lambda do x end 49 | } 50 | @thing.class.send(:define_method, :m5, &(hash[:blk])) 51 | @thing.method(:m5).should.be having_source(%( 52 | def m5; x; end 53 | )) 54 | end 55 | 56 | unless has_parsetree? 57 | should "raise Sourcify::CannotParseEvalCodeError when method is created from eval" do 58 | lambda { eval("klass = Class.new { define_method(:m6){ x }; }; klass.new.method(:m6)").to_source }. 59 | should.raise(Sourcify::CannotParseEvalCodeError) 60 | end 61 | end 62 | 63 | end 64 | -------------------------------------------------------------------------------- /spec/method/raw_scanner/block_comment_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Method's raw scanner > block comment (=begin ... =end)" do 5 | extend Sourcify::Method::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Block comment (=begin ... =end)" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/method/raw_scanner/double_colons_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Method's raw scanner > double colons" do 5 | extend Sourcify::Method::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Double colons" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/method/raw_scanner/double_quote_str_w_interpolation_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Method's raw scanner > double quote strings (w interpolation)" do 5 | extend Sourcify::Method::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Double quote strings (w interpolation)" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/method/raw_scanner/double_quote_str_wo_interpolation_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Method's raw scanner > double quote strings (wo interpolation)" do 5 | extend Sourcify::Method::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Double quote strings (wo interpolation)" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/method/raw_scanner/heredoc_w_indent_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Method's raw scanner > heredoc (w indent)" do 5 | extend Sourcify::Method::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Heredoc (w indent)" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/method/raw_scanner/heredoc_wo_indent_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Method's raw scanner > heredoc (wo indent)" do 5 | extend Sourcify::Method::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Heredoc (wo indent)" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/method/raw_scanner/kw_block_start_alias1_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Method's raw scanner > keyword block start alias #1 (incrementing counter by 1)" do 5 | 6 | extend Sourcify::Method::Parser::RawScanner::Spec::KwBlockStartSupport 7 | behaves_like "Keyword block start alias #1 (incrementing counter by 1)" 8 | 9 | kw_block_start_alias1.each do |kw| 10 | should "increment counter with ... def #{kw} ..." do 11 | kw_block_start_counter(< keyword block start alias #2 (incrementing counter by 0..1)" do 5 | 6 | extend Sourcify::Method::Parser::RawScanner::Spec::KwBlockStartSupport 7 | behaves_like "Keyword block start alias #2 (incrementing counter by 0..1)" 8 | 9 | kw_block_start_alias2.each do |kw| 10 | should "increment counter with ... def #{kw} ..." do 11 | kw_block_start_counter(< per line comment (# ...)" do 5 | extend Sourcify::Method::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Per line comment (# ...)" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/method/raw_scanner/single_quote_str_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Method's raw scanner > single quote strings (\', %q & %w)" do 5 | extend Sourcify::Method::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like 'Single quote strings (\', %q & %w)' 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/method/raw_scanner/slash_operator_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Method's raw scanner > slash operator" do 5 | extend Sourcify::Method::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like 'Slash operator' 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/method/raw_scanner/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../../spec_helper', __FILE__) 2 | require File.expand_path('../../../raw_scanner/shared_specs', __FILE__) 3 | 4 | module Sourcify::Method::Parser::RawScanner 5 | 6 | SCANNER = self 7 | 8 | class << self 9 | attr_reader :tokens, :counter 10 | end 11 | 12 | module Spec 13 | 14 | module GenericSupport 15 | def self.extended(base) 16 | base.instance_eval do 17 | 18 | before do 19 | SCANNER.instance_eval do 20 | class << self 21 | alias_method :orig_stop_if_probably_defined_by_proc, 22 | :stop_if_probably_defined_by_proc 23 | def stop_if_probably_defined_by_proc; end 24 | end 25 | end 26 | end 27 | 28 | after do 29 | SCANNER.instance_eval do 30 | class << self 31 | alias_method :stop_if_probably_defined_by_proc, 32 | :orig_stop_if_probably_defined_by_proc 33 | end 34 | end 35 | end 36 | 37 | def process(data) 38 | SCANNER.process(data) 39 | SCANNER.tokens 40 | end 41 | 42 | end 43 | end 44 | end 45 | 46 | module KwBlockStartSupport 47 | def self.extended(base) 48 | base.instance_eval do 49 | 50 | before do 51 | Extensions::Counter.class_eval do 52 | alias_method :orig_started?, :started? 53 | def started?; true; end 54 | end 55 | end 56 | 57 | after do 58 | Extensions::Counter.class_eval do 59 | alias_method :started?, :orig_started? 60 | end 61 | end 62 | 63 | def kw_block_start_counter(data) 64 | SCANNER.process(data) 65 | SCANNER.counter.counts 66 | end 67 | 68 | def kw_block_start_alias1 69 | %w{class do module begin case module if unless} 70 | end 71 | 72 | def kw_block_start_alias2 73 | %w{while until for} 74 | end 75 | end 76 | end 77 | end 78 | 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /spec/method/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'spec_helper') 2 | -------------------------------------------------------------------------------- /spec/method/to_raw_source_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Method#to_raw_source" do 4 | 5 | should 'retain comments' do 6 | def m1 7 | a = 1 8 | # i should stay !! 9 | end 10 | method(:m1).should.be having_raw_source(%( 11 | def m1 12 | a = 1 13 | # i should stay !! 14 | end 15 | )) 16 | end 17 | 18 | should 'retain last nil statement' do 19 | def m2 20 | a = 1 21 | nil 22 | end 23 | method(:m2).should.be having_raw_source(%( 24 | def m2 25 | a = 1 26 | nil 27 | end 28 | )) 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /spec/method/to_sexp_from_def_end_block_w_variables_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_sexp (from def..end block)' do 4 | describe 'variables' do 5 | 6 | should 'handle non var' do 7 | def m1; x; end 8 | method(:m1).should.be having_sexp( 9 | s(:defn, :m1, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 10 | ) 11 | end 12 | 13 | should 'not handle local var' do 14 | x = 'lx'; 15 | def m2; x; end 16 | method(:m2).should.be having_sexp( 17 | s(:defn, :m2, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 18 | ) 19 | end 20 | 21 | should 'handle instance var' do 22 | @x = 'ix' 23 | def m3; @x; end 24 | method(:m3).should.be having_sexp( 25 | s(:defn, :m3, s(:args), s(:scope, s(:block, s(:ivar, :@x)))) 26 | ) 27 | end 28 | 29 | should 'handle class var' do 30 | @@x = 'cx' 31 | def m4; @@x; end 32 | method(:m4).should.be having_sexp( 33 | s(:defn, :m4, s(:args), s(:scope, s(:block, s(:cvar, :@@x)))) 34 | ) 35 | end 36 | 37 | should 'handle global var' do 38 | $x = 'gx' 39 | def m5; $x; end 40 | method(:m5).should.be having_sexp( 41 | s(:defn, :m5, s(:args), s(:scope, s(:block, s(:gvar, :$x)))) 42 | ) 43 | end 44 | 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /spec/method/to_sexp_from_def_end_block_within_irb_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_sexp (from def..end block)' do 4 | describe 'within IRB' do 5 | 6 | class << self 7 | 8 | def irb_eval(string) 9 | irb_exec(string)[-1] 10 | end 11 | 12 | def equal_to(expected) 13 | lambda {|found| found == expected } 14 | end 15 | 16 | end 17 | 18 | should 'handle non var' do 19 | irb_eval(%( 20 | def m1; x; end 21 | method(:m1).to_sexp 22 | )).should.be equal_to( 23 | s(:defn, :m1, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 24 | ) 25 | end 26 | 27 | should 'not handle local var' do 28 | irb_eval(%( 29 | x = :lx 30 | def m2; x; end 31 | method(:m2).to_sexp 32 | )).should.be equal_to( 33 | s(:defn, :m2, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 34 | ) 35 | end 36 | 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/method/to_sexp_from_def_end_block_within_pry_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_sexp (from def..end block)' do 4 | describe 'within PRY' do 5 | 6 | class << self 7 | 8 | def pry_eval(string) 9 | pry_exec(string)[-1] 10 | end 11 | 12 | def equal_to(expected) 13 | lambda {|found| found == expected } 14 | end 15 | 16 | end 17 | 18 | should 'handle non var' do 19 | pry_eval(%( 20 | def m1; x; end 21 | method(:m1).to_sexp 22 | )).should.be equal_to( 23 | s(:defn, :m1, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 24 | ) 25 | end 26 | 27 | should 'not handle local var' do 28 | pry_eval(%( 29 | x = :lx 30 | def m2; x; end 31 | method(:m2).to_sexp 32 | )).should.be equal_to( 33 | s(:defn, :m2, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 34 | ) 35 | end 36 | 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/method/to_sexp_from_define_method_w_multi_blocks_and_specified_attached_to_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_sexp (from define_method)' do 4 | describe 'w specified {:attached_to => ...}' do 5 | 6 | # NOTE: We just want enough specs to show that handling of :attached_to 7 | # works for Method#to_sexp as well. 8 | 9 | before { @thing = Object.new } 10 | options = {:attached_to => /^.*?(\W|)watever(\W)/} 11 | 12 | should 'handle no nesting on same line' do 13 | b1 = lambda {|a| @x1+1 }; b2 = watever { @x1+2 }; b3 = lambda { @x1+3 } 14 | @thing.class.send(:define_method, :m1, &b2) 15 | @thing.method(:m1).should.be having_sexp( 16 | s(:defn, 17 | :m1, 18 | s(:args), 19 | s(:scope, s(:block, s(:call, s(:ivar, :@x1), :+, s(:arglist, s(:lit, 2)))))), 20 | options 21 | ) 22 | end 23 | 24 | should 'handle single level nesting on same line' do 25 | b1 = lambda {|a| @x2+1 }; b2 = watever { lambda { @x2+2 } } 26 | @thing.class.send(:define_method, :m2, &b2) 27 | @thing.method(:m2).should.be having_sexp( 28 | s(:defn, 29 | :m2, 30 | s(:args), 31 | s(:scope, 32 | s(:block, 33 | s(:iter, 34 | s(:call, nil, :lambda, s(:arglist)), 35 | nil, 36 | s(:call, s(:ivar, :@x2), :+, s(:arglist, s(:lit, 2))))))), 37 | options 38 | ) 39 | end 40 | 41 | should 'handle multi level nesting on same line' do 42 | b2 = (lambda {|a| watever { lambda { @x3 } } }).call(1) 43 | @thing.class.send(:define_method, :m3, &b2) 44 | @thing.method(:m3).should.be having_sexp( 45 | s(:defn, 46 | :m3, 47 | s(:args), 48 | s(:scope, 49 | s(:block, 50 | s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:ivar, :@x3))))), 51 | options 52 | ) 53 | end 54 | 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/method/to_sexp_from_define_method_w_variables_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_sexp (from define_method)' do 4 | describe 'variables' do 5 | 6 | before { @thing = Object.new } 7 | 8 | should 'handle non var' do 9 | blk = lambda { x } 10 | @thing.class.send(:define_method, :m1, &blk) 11 | @thing.method(:m1).should.be having_sexp( 12 | s(:defn, :m1, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 13 | ) 14 | end 15 | 16 | should 'not handle local var' do 17 | # NOTE: This can be a potential bug, cos we purposely ignore the local 18 | # var captured in the proc's binding ... anyway, we see how things go 19 | # (eg. maybe nobody would ever care abt it) 20 | x, blk = 'lx', lambda { x } 21 | @thing.class.send(:define_method, :m2, &blk) 22 | @thing.method(:m2).should.be having_sexp( 23 | s(:defn, :m2, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 24 | ) 25 | end 26 | 27 | should 'handle instance var' do 28 | @x, blk = 'ix', lambda { @x } 29 | @thing.class.send(:define_method, :m3, &blk) 30 | method(:m3).should.be having_sexp( 31 | s(:defn, :m3, s(:args), s(:scope, s(:block, s(:ivar, :@x)))) 32 | ) 33 | end 34 | 35 | should 'handle class var' do 36 | @@x, blk = 'cx', lambda { @@x } 37 | @thing.class.send(:define_method, :m4, &blk) 38 | method(:m4).should.be having_sexp( 39 | s(:defn, :m4, s(:args), s(:scope, s(:block, s(:cvar, :@@x)))) 40 | ) 41 | end 42 | 43 | should 'handle global var' do 44 | $x, blk = 'gx', lambda { $x } 45 | @thing.class.send(:define_method, :m5, &blk) 46 | method(:m5).should.be having_sexp( 47 | s(:defn, :m5, s(:args), s(:scope, s(:block, s(:gvar, :$x)))) 48 | ) 49 | end 50 | 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/method/to_sexp_from_define_method_within_irb_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_sexp (from define_method)' do 4 | describe 'within IRB' do 5 | 6 | class << self 7 | 8 | def irb_eval(string) 9 | irb_exec(string)[-1] 10 | end 11 | 12 | def equal_to(expected) 13 | lambda {|found| found == expected } 14 | end 15 | 16 | end 17 | 18 | should 'handle non var' do 19 | irb_eval(%\ 20 | thing = Object.new 21 | blk = lambda { x } 22 | thing.class.send(:define_method, :m1, &blk) 23 | thing.method(:m1).to_sexp 24 | \).should.be equal_to( 25 | s(:defn, :m1, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 26 | ) 27 | end 28 | 29 | should 'not handle local var' do 30 | irb_eval(%\ 31 | thing = Object.new 32 | x = :lx 33 | blk = lambda { x } 34 | thing.class.send(:define_method, :m2, &blk) 35 | thing.method(:m2).to_sexp 36 | \).should.be equal_to( 37 | s(:defn, :m2, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 38 | ) 39 | end 40 | 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/method/to_sexp_from_define_method_within_pry_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_sexp (from define_method)' do 4 | describe 'within PRY' do 5 | 6 | class << self 7 | 8 | def pry_eval(string) 9 | pry_exec(string)[-1] 10 | end 11 | 12 | def equal_to(expected) 13 | lambda {|found| found == expected } 14 | end 15 | 16 | end 17 | 18 | should 'handle non var' do 19 | pry_eval(%\ 20 | thing = Object.new 21 | blk = lambda { x } 22 | thing.class.send(:define_method, :m1, &blk) 23 | thing.method(:m1).to_sexp 24 | \).should.be equal_to( 25 | s(:defn, :m1, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 26 | ) 27 | end 28 | 29 | should 'not handle local var' do 30 | pry_eval(%\ 31 | thing = Object.new 32 | x = :lx 33 | blk = lambda { x } 34 | thing.class.send(:define_method, :m2, &blk) 35 | thing.method(:m2).to_sexp 36 | \).should.be equal_to( 37 | s(:defn, :m2, s(:args), s(:scope, s(:block, s(:call, nil, :x, s(:arglist))))) 38 | ) 39 | end 40 | 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/method/to_sexp_w_specified_strip_enclosure_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_sexp' do 4 | describe 'w specified {:strip_enclosure => ...}' do 5 | 6 | describe '>> w true' do 7 | 8 | options = {:strip_enclosure => true} 9 | 10 | should 'strip enclosing proc wo arg' do 11 | def m1; a+b; end 12 | method(:m1).should.be having_sexp( 13 | s(:scope, 14 | s(:block, 15 | s(:call, 16 | s(:call, nil, :a, s(:arglist)), 17 | :+, 18 | s(:arglist, s(:call, nil, :b, s(:arglist)))))), 19 | options 20 | ) 21 | end 22 | 23 | should 'strip enclosing proc w arg' do 24 | def m2(a); a+b; end 25 | method(:m2).should.be having_sexp( 26 | s(:scope, 27 | s(:block, 28 | s(:call, 29 | s(:lvar, :a), 30 | :+, 31 | s(:arglist, s(:call, nil, :b, s(:arglist)))))), 32 | options 33 | ) 34 | end 35 | 36 | end 37 | 38 | describe '>> w false' do 39 | 40 | options = {:strip_enclosure => false} 41 | 42 | should 'not strip enclosing proc wo arg' do 43 | def m3; a+b; end 44 | method(:m3).should.be having_sexp( 45 | s(:defn, 46 | :m3, 47 | s(:args), 48 | s(:scope, 49 | s(:block, 50 | s(:call, 51 | s(:call, nil, :a, s(:arglist)), 52 | :+, 53 | s(:arglist, s(:call, nil, :b, s(:arglist))))))), 54 | options 55 | ) 56 | end 57 | 58 | should 'not strip enclosing proc w arg' do 59 | def m4(a); a+b; end 60 | method(:m4).should.be having_sexp( 61 | s(:defn, 62 | :m4, 63 | s(:args, :a), 64 | s(:scope, 65 | s(:block, 66 | s(:call, s(:lvar, :a), :+, s(:arglist, s(:call, nil, :b, s(:arglist))))))), 67 | options 68 | ) 69 | end 70 | 71 | end 72 | 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_w_19_extras_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Method#to_source (from def ... end block)" do 4 | describe "w 19 extras" do 5 | if RUBY_VERSION.include?('1.9.') 6 | 7 | should 'handle simple (w label keys)' do 8 | def m1; {a: 1, b: 2}; end 9 | method(:m1).should.be having_source(%( 10 | def m1; {:a => 1, :b => 2}; end 11 | )) 12 | end 13 | 14 | should 'handle nested (w label keys)' do 15 | def m2; {a: 1, b: {c: 3}}; end 16 | method(:m2).should.be having_source(%( 17 | def m2; {:a => 1, :b => {:c => 3}}; end 18 | )) 19 | end 20 | 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_w_nested_begin_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from def ... end block)' do 4 | describe 'w nested begin' do 5 | 6 | should 'handle simple' do 7 | def m1 8 | begin @x1 = 1 end 9 | end 10 | method(:m1).should.be having_source(%( 11 | def m1 12 | begin @x1 = 1 end 13 | end 14 | )) 15 | end 16 | 17 | should 'handle nested' do 18 | def m2 19 | begin 20 | @x1 = 1 21 | begin @x2 = 2 end 22 | end 23 | end 24 | method(:m2).should.be having_source(%( 25 | def m2 26 | begin 27 | @x1 = 1 28 | begin @x2 = 2 end 29 | end 30 | end 31 | )) 32 | end 33 | 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_w_nested_case_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Method#to_source (from def ... end block)" do 4 | describe "w nested case" do 5 | 6 | should 'handle simple' do 7 | def m1 8 | case @x1 when true then false end 9 | end 10 | method(:m1).should.be having_source(%( 11 | def m1 12 | case @x1 when true then false end 13 | end 14 | )) 15 | end 16 | 17 | should 'handle nested' do 18 | def m2 19 | case @x1 20 | when true 21 | case @x2 when false then true end 22 | end 23 | end 24 | method(:m2).should.be having_source(%( 25 | def m2 26 | case @x1 27 | when true 28 | case @x2 when false then true end 29 | end 30 | end 31 | )) 32 | end 33 | 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_w_nested_class_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Method#to_source (from def ... end block)" do 4 | describe "w nested class" do 5 | 6 | class AA; end 7 | 8 | should 'handle singleton' do 9 | def m1 10 | class << AA 11 | def aa 12 | @x1 = 1 13 | end 14 | end 15 | end 16 | method(:m1).should.be having_source(%( 17 | def m1 18 | class << AA 19 | def aa 20 | @x1 = 1 21 | end 22 | end 23 | end 24 | )) 25 | end 26 | 27 | should 'handle nested' do 28 | def m2 29 | class << AA 30 | class BB 31 | def bb 32 | @x1 = 1 33 | end 34 | end 35 | end 36 | end 37 | method(:m2).should.be having_source(%( 38 | def m2 39 | class << AA 40 | class BB 41 | def bb 42 | @x1 = 1 43 | end 44 | end 45 | end 46 | end 47 | )) 48 | end 49 | 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_w_nested_do_end_block_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Method#to_source (from def ... end block)" do 4 | describe "w nested do ... end block" do 5 | 6 | should 'handle simple' do 7 | def m1 8 | lambda do @x1 = 1 end 9 | end 10 | method(:m1).should.be having_source(%( 11 | def m1 12 | lambda { @x1 = 1 } 13 | end 14 | )) 15 | end 16 | 17 | should 'handle nested' do 18 | def m2 19 | lambda do 20 | lambda do @x1 = 1 end 21 | end 22 | end 23 | method(:m2).should.be having_source(%( 24 | def m2 25 | lambda do 26 | lambda { @x1 = 1 } 27 | end 28 | end 29 | )) 30 | end 31 | 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_w_nested_for_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Method#to_source (from def ... end block)" do 4 | describe "w nested for block" do 5 | 6 | should 'handle w do' do 7 | def m1 8 | for x1 in [1,2] do x1 end 9 | end 10 | method(:m1).should.be having_source(%( 11 | def m1 12 | for x1 in [1,2] do x1 end 13 | end 14 | )) 15 | end 16 | 17 | should 'handle w \ do' do 18 | def m2 19 | for x2 in [1,2] \ 20 | do x2 end 21 | end 22 | method(:m2).should.be having_source(%( 23 | def m2 24 | for x2 in [1,2] do x2 end 25 | end 26 | )) 27 | end 28 | 29 | should 'handle wo do (w newline)' do 30 | def m3 31 | for x3 in [1,2] 32 | x3 33 | end 34 | end 35 | method(:m3).should.be having_source(%( 36 | def m3 37 | for x3 in [1,2] 38 | x3 39 | end 40 | end 41 | )) 42 | end 43 | 44 | should 'handle wo do (w semicolon)' do 45 | def m4 46 | for x4 in [1,2]; x4; end 47 | end 48 | method(:m4).should.be having_source(%( 49 | def m4 50 | for x4 in [1,2] 51 | x4 52 | end 53 | end 54 | )) 55 | end 56 | 57 | should 'handle nested wo do within w do' do 58 | def m5 59 | for x1 in [1,2] do 60 | for x2 in [1,2] 61 | x2 62 | end 63 | end 64 | end 65 | method(:m5).should.be having_source(%( 66 | def m5 67 | for x1 in [1,2] do 68 | for x2 in [1,2] 69 | x2 70 | end 71 | end 72 | end 73 | )) 74 | end 75 | 76 | should 'handle nested wo do within wo do' do 77 | def m6 78 | for x1 in [2,3] 79 | for x2 in [2,3] 80 | x2 81 | end 82 | end 83 | end 84 | method(:m6).should.be having_source(%( 85 | def m6 86 | for x1 in [2,3] do 87 | for x2 in [2,3] 88 | x2 89 | end 90 | end 91 | end 92 | )) 93 | end 94 | 95 | should 'handle nested w do within wo do' do 96 | def m7 97 | for x1 in [3,4] 98 | for x2 in [3,4] do x2 end 99 | end 100 | end 101 | method(:m7).should.be having_source(%( 102 | def m7 103 | for x1 in [3,4] 104 | for x2 in [3,4] do x2 end 105 | end 106 | end 107 | )) 108 | end 109 | 110 | should 'handle nested w do within w do' do 111 | def m8 112 | for x1 in [4,5] \ 113 | do for x2 in [4,5] do x2 end 114 | end 115 | end 116 | method(:m8).should.be having_source(%( 117 | def m8 118 | for x1 in [4,5] 119 | for x2 in [4,5] do x2 end 120 | end 121 | end 122 | )) 123 | end 124 | 125 | end 126 | end 127 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_w_nested_if_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Method#to_source (from def ... end block)" do 4 | describe "w nested if" do 5 | 6 | should 'handle simple block' do 7 | def m1 8 | if @x1 then @x1 = 1 end 9 | end 10 | method(:m1).should.be having_source(%( 11 | def m1 12 | if @x1 then @x1 = 1 end 13 | end 14 | )) 15 | end 16 | 17 | should 'handle nested block' do 18 | def m2 19 | if @x1 20 | if @x2 then @x2 = 1 end 21 | end 22 | end 23 | method(:m2).should.be having_source(%( 24 | def m2 25 | if @x1 26 | if @x2 then @x2 = 1 end 27 | end 28 | end 29 | )) 30 | end 31 | 32 | should 'handle simple modifier' do 33 | def m3 34 | @x1 = 1 if true 35 | end 36 | method(:m3).should.be having_source(%( 37 | def m3 38 | @x1 = 1 if true 39 | end 40 | )) 41 | end 42 | 43 | # NOTE: Syntatically correct, but the RubyParser-2.3.* can't handle it. 44 | # should 'handle block within modifier' do 45 | # def m4 46 | # @x1 = 1 if (if @x1 then true end) 47 | # end 48 | # method(:m4).should.be having_source(%( 49 | # def m4 50 | # @x1 = 1 if (if @x1 then true end) 51 | # end 52 | # )) 53 | # end 54 | 55 | should 'handle modifier w trailing backslash' do 56 | def m5 57 | @x1 = 1 \ 58 | if true 59 | end 60 | method(:m5).should.be having_source(%( 61 | def m5 62 | @x1 = 1 if true 63 | end 64 | )) 65 | end 66 | 67 | should 'handle modifier within block' do 68 | def m6 69 | if @x1 70 | @x1 = 1 if @x2 71 | end 72 | end 73 | method(:m6).should.be having_source(%( 74 | def m6 75 | if @x1 76 | @x1 = 1 if @x2 77 | end 78 | end 79 | )) 80 | end 81 | 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_w_nested_literal_keyword_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Method#to_source (from def ... end block)" do 4 | describe "w nested literal keyword" do 5 | 6 | # See http://redmine.ruby-lang.org/issues/show/3764 7 | 8 | should 'handle :class' do 9 | def m1 10 | x = :class 11 | end 12 | method(:m1).should.be having_source(%( 13 | def m1 14 | x = :class 15 | end 16 | )) 17 | end 18 | 19 | should 'handle :module' do 20 | def m2 21 | x = :module 22 | end 23 | method(:m2).should.be having_source(%( 24 | def m2 25 | x = :module 26 | end 27 | )) 28 | end 29 | 30 | should 'handle :def' do 31 | def m3 32 | x = :def 33 | end 34 | method(:m3).should.be having_source(%( 35 | def m3 36 | x = :def 37 | end 38 | )) 39 | end 40 | 41 | should 'handle :if' do 42 | def m4 43 | x = :if 44 | end 45 | method(:m4).should.be having_source(%( 46 | def m4 47 | x = :if 48 | end 49 | )) 50 | end 51 | 52 | should 'handle :unless' do 53 | def m5 54 | x = :unless 55 | end 56 | method(:m5).should.be having_source(%( 57 | def m5 58 | x = :unless 59 | end 60 | )) 61 | end 62 | 63 | should 'handle :for' do 64 | def m6 65 | x = :for 66 | end 67 | method(:m6).should.be having_source(%( 68 | def m6 69 | x = :for 70 | end 71 | )) 72 | end 73 | 74 | should 'handle :while' do 75 | def m7 76 | x = :while 77 | end 78 | method(:m7).should.be having_source(%( 79 | def m7 80 | x = :while 81 | end 82 | )) 83 | end 84 | 85 | should 'handle :until' do 86 | def m8 87 | x = :until 88 | end 89 | method(:m8).should.be having_source(%( 90 | def m8 91 | x = :until 92 | end 93 | )) 94 | end 95 | 96 | should 'handle :begin' do 97 | def m9 98 | x = :begin 99 | end 100 | method(:m9).should.be having_source(%( 101 | def m9 102 | x = :begin 103 | end 104 | )) 105 | end 106 | 107 | should 'handle :case' do 108 | def m10 109 | x = :case 110 | end 111 | method(:m10).should.be having_source(%( 112 | def m10 113 | x = :case 114 | end 115 | )) 116 | end 117 | 118 | should 'handle :do' do 119 | def m11 120 | x = :do 121 | end 122 | method(:m11).should.be having_source(%( 123 | def m11 124 | x = :do 125 | end 126 | )) 127 | end 128 | 129 | should 'handle :end' do 130 | def m12 131 | x = :end 132 | end 133 | method(:m12).should.be having_source(%( 134 | def m12 135 | x = :end 136 | end 137 | )) 138 | end 139 | 140 | end 141 | end 142 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_w_nested_method_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Method#to_source (from def ... end block)" do 4 | describe "w nested method" do 5 | 6 | should 'handle simple' do 7 | def m1 8 | def aa; x = 1; end 9 | end 10 | method(:m1).should.be having_source(%( 11 | def m1 12 | def aa; x = 1; end 13 | end 14 | )) 15 | end 16 | 17 | should 'handle nested' do 18 | def m2 19 | def aa 20 | def bb; x = 2; end 21 | end 22 | end 23 | method(:m2).should.be having_source(%( 24 | def m2 25 | def aa 26 | def bb; x = 2; end 27 | end 28 | end 29 | )) 30 | end 31 | 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_w_nested_module_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Method#to_source (from def ... end block)" do 4 | describe "w nested module" do 5 | 6 | class AA; end 7 | 8 | should 'handle simple' do 9 | def m1 10 | class << AA 11 | module BB 12 | def aa 13 | @x1 = 1 14 | end 15 | end 16 | end 17 | end 18 | method(:m1).should.be having_source(%( 19 | def m1 20 | class << AA 21 | module BB 22 | def aa 23 | @x1 = 1 24 | end 25 | end 26 | end 27 | end 28 | )) 29 | end 30 | 31 | should 'handle nested' do 32 | def m2 33 | class << AA 34 | module BB 35 | module CC 36 | def bb 37 | @x1 = 1 38 | end 39 | end 40 | end 41 | end 42 | end 43 | method(:m2).should.be having_source(%( 44 | def m2 45 | class << AA 46 | module BB 47 | module CC 48 | def bb 49 | @x1 = 1 50 | end 51 | end 52 | end 53 | end 54 | end 55 | )) 56 | end 57 | 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_w_nested_unless_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Method#to_source (from def ... end block)" do 4 | describe "w nested unless" do 5 | 6 | should 'handle simple block' do 7 | def m1 8 | unless @x1 then @x1 = 1 end 9 | end 10 | method(:m1).should.be having_source(%( 11 | def m1 12 | unless @x1 then @x1 = 1 end 13 | end 14 | )) 15 | end 16 | 17 | should 'handle nested block' do 18 | def m2 19 | unless @x1 20 | unless @x2 then @x2 = 1 end 21 | end 22 | end 23 | method(:m2).should.be having_source(%( 24 | def m2 25 | unless @x1 26 | unless @x2 then @x2 = 1 end 27 | end 28 | end 29 | )) 30 | end 31 | 32 | should 'handle simple modifier' do 33 | def m3 34 | @x1 = 1 unless true 35 | end 36 | method(:m3).should.be having_source(%( 37 | def m3 38 | @x1 = 1 unless true 39 | end 40 | )) 41 | end 42 | 43 | # NOTE: Syntatically correct, but the RubyParser-2.3.* can't handle it. 44 | # should 'handle block within modifier' do 45 | # def m4 46 | # @x1 = 1 unless (unless @x1 then true end) 47 | # end 48 | # method(:m4).should.be having_source(%( 49 | # def m4 50 | # @x1 = 1 unless (unless @x1 then true end) 51 | # end 52 | # )) 53 | # end 54 | 55 | should 'handle modifier within block' do 56 | def m5 57 | unless @x1 58 | @x1 = 1 unless @x2 59 | end 60 | end 61 | method(:m5).should.be having_source(%( 62 | def m5 63 | unless @x1 64 | @x1 = 1 unless @x2 65 | end 66 | end 67 | )) 68 | end 69 | 70 | should 'handle modifier w trailing backslash' do 71 | def m6 72 | @x1 = 1 \ 73 | unless true 74 | end 75 | method(:m6).should.be having_source(%( 76 | def m6 77 | @x1 = 1 unless true 78 | end 79 | )) 80 | end 81 | 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_w_singleton_method_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from def ... end block)' do 4 | describe 'w singleton method' do 5 | 6 | should 'strip object' do 7 | thing = Object.new 8 | def m 9 | @x1 = 1 10 | end 11 | method(:m).should.be having_source(%( 12 | def m 13 | @x1 = 1 14 | end 15 | )) 16 | end 17 | 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_within_irb_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from def..end block)' do 4 | describe 'within IRB' do 5 | 6 | class << self 7 | 8 | def irb_eval(string) 9 | irb_exec(string)[-1] 10 | end 11 | 12 | def equal_to(expected) 13 | lambda {|found| normalize_code(found) == normalize_code(expected) } 14 | end 15 | 16 | end 17 | 18 | should 'handle' do 19 | irb_eval(%( 20 | def m1; x; end 21 | method(:m1).to_source 22 | )).should.be equal_to(%( 23 | def m1 24 | x 25 | end 26 | )) 27 | end 28 | 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_block_within_pry_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from def..end block)' do 4 | describe 'within PRY' do 5 | 6 | class << self 7 | 8 | def pry_eval(string) 9 | pry_exec(string)[-1] 10 | end 11 | 12 | def equal_to(expected) 13 | lambda {|found| normalize_code(found) == normalize_code(expected) } 14 | end 15 | 16 | end 17 | 18 | should 'handle' do 19 | pry_eval(%( 20 | def m1; x; end 21 | method(:m1).to_source 22 | )).should.be equal_to(%( 23 | def m1 24 | x 25 | end 26 | )) 27 | end 28 | 29 | should 'handle upward scroll' do 30 | pry_eval(%Q( 31 | def m1; x1; end 32 | def m2; x2; end 33 | method(:m1) 34 | method(:m1).to_source 35 | method(:m2).to_source 36 |  37 | )).should.be equal_to(%( 38 | def m1 39 | x1 40 | end 41 | )) 42 | end 43 | 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_w_multi_blocks_and_many_matches_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from def...end block)' do 4 | describe 'w multi blocks and many matches' do 5 | 6 | if has_parsetree? 7 | # TODO: Should we support this ?? 8 | else 9 | 10 | error = Sourcify::MultipleMatchingMethodsPerLineError 11 | 12 | should "raise #{error} w no nesting on same line" do 13 | def m1; @x1; end; def m1; @x2; end 14 | lambda { method(:m1).to_source }.should.raise(error) 15 | end 16 | 17 | should "raise #{error} w single level nesting on same line" do 18 | def m2; class << self; def m2; @x1; end; end; end 19 | lambda { method(:m2).to_source }.should.raise(error) 20 | end 21 | 22 | should "raise #{error} w multi level nesting on same line" do 23 | def m3; class << self; def m3; class << self; def m3; @x1; end; end; end; end; end 24 | lambda { method(:m3).to_source }.should.raise(error) 25 | end 26 | 27 | end 28 | 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/method/to_source_from_def_end_w_multi_blocks_and_single_match_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from def...end)' do 4 | describe 'w single blocks and many matches' do 5 | 6 | should 'skip non-matching w no nesting on same line' do 7 | def m1(a); @x1; end; def m1(b); @x2; end 8 | method(:m1).should.be having_source(%( 9 | def m1(b) 10 | @x2 11 | end 12 | )) 13 | end 14 | 15 | should 'skip non-matching w single level nesting on same line' do 16 | def m2(a); class << self; def m2(b); @x1; end; end; end 17 | m2(1) # calling m2 has the side effect of redefining m2 18 | method(:m2).should.be having_source(%( 19 | def m2(b) 20 | @x1 21 | end 22 | )) 23 | end 24 | 25 | should 'skip non-matching w multi level nesting on same line' do 26 | def m3(a); class << self; def m3(b); class << self; def m3(c); @x1; end; end; end; end; end 27 | m3(1); m3(2) # calling m3 twice has the side effect of redefining m3 twice 28 | method(:m3).should.be having_source(%( 29 | def m3(c) 30 | @x1 31 | end 32 | )) 33 | end 34 | 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/method/to_source_from_define_method_w_braced_block_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Method#to_source (from define_method)" do 4 | describe "w braced block" do 5 | 6 | before { @thing = Object.new } 7 | 8 | describe 'w block declared elsewhere' do 9 | 10 | should 'wo arg' do 11 | blk = lambda { x = 1 } 12 | @thing.class.send(:define_method, :m1, &blk) 13 | @thing.method(:m1).should.be having_source(%( 14 | def m1 15 | x = 1 16 | end 17 | )) 18 | end 19 | 20 | should 'w one required arg' do 21 | blk = lambda {|a| x = 1 } 22 | @thing.class.send(:define_method, :m2, &blk) 23 | @thing.method(:m2).should.be having_source(%( 24 | def m2(a) 25 | x = 1 26 | end 27 | )) 28 | end 29 | 30 | should 'w one optional arg' do 31 | blk = lambda {|a=1| x = 1 } 32 | @thing.class.send(:define_method, :m3, &blk) 33 | @thing.method(:m3).should.be having_source(%( 34 | def m3(a = 1) 35 | x = 1 36 | end 37 | )) 38 | end 39 | 40 | should 'w multiple required args' do 41 | blk = lambda {|a, b, c| x = 1 } 42 | @thing.class.send(:define_method, :m5, &blk) 43 | @thing.method(:m5).should.be having_source(%( 44 | def m5(a, b, c) 45 | x = 1 46 | end 47 | )) 48 | end 49 | 50 | should 'w multiple args w one optional' do 51 | blk = lambda {|a, b, c=1| x = 1 } 52 | @thing.class.send(:define_method, :m6, &blk) 53 | @thing.method(:m6).should.be having_source(%( 54 | def m6(a, b, c = 1) 55 | x = 1 56 | end 57 | )) 58 | end 59 | 60 | end 61 | 62 | 63 | describe 'w block attached' do 64 | 65 | should 'wo arg' do 66 | @thing.class.send(:define_method, :m1) { x = 1 } 67 | @thing.method(:m1).should.be having_source(%( 68 | def m1 69 | x = 1 70 | end 71 | )) 72 | end 73 | 74 | should 'w one required arg' do 75 | @thing.class.send(:define_method, :m2) {|a| x = 1 } 76 | @thing.method(:m2).should.be having_source(%( 77 | def m2(a) 78 | x = 1 79 | end 80 | )) 81 | end 82 | 83 | should 'w one optional arg' do 84 | @thing.class.send(:define_method, :m3) {|a=1| x = 1 } 85 | @thing.method(:m3).should.be having_source(%( 86 | def m3(a = 1) 87 | x = 1 88 | end 89 | )) 90 | end 91 | 92 | should 'w multiple required args' do 93 | @thing.class.send(:define_method, :m5) {|a, b, c| x = 1 } 94 | @thing.method(:m5).should.be having_source(%( 95 | def m5(a, b, c) 96 | x = 1 97 | end 98 | )) 99 | end 100 | 101 | should 'w multiple args w one optional' do 102 | @thing.class.send(:define_method, :m6) {|a, b, c=1| x = 1 } 103 | @thing.method(:m6).should.be having_source(%( 104 | def m6(a, b, c = 1) 105 | x = 1 106 | end 107 | )) 108 | end 109 | 110 | end 111 | 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /spec/method/to_source_from_define_method_w_multi_blocks_and_many_matches_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from #define_method)' do 4 | describe 'w multi blocks and many matches' do 5 | 6 | if has_parsetree? 7 | # TODO: Should we support this ?? 8 | else 9 | 10 | before { @thing = Object.new } 11 | error = Sourcify::MultipleMatchingProcsPerLineError 12 | 13 | describe 'w do...end block' do 14 | should "raise #{error} w no nesting on same line" do 15 | b1 = lambda do |a| @x end; b2 = lambda do @x end; b3 = lambda do @x end 16 | @thing.class.send(:define_method, :m1, &b2) 17 | lambda { @thing.method(:m1).to_source }.should.raise(error) 18 | end 19 | 20 | should "raise #{error} w single level nesting on same line" do 21 | b1 = lambda do |a| @x end; b2 = lambda do lambda do @x end end 22 | @thing.class.send(:define_method, :m2, &b2) 23 | lambda { @thing.method(:m2).to_source }.should.raise(error) 24 | end 25 | 26 | should "raise #{error} w multi level nesting on same line" do 27 | b2 = (lambda do |a| lambda do lambda do @x end end end).call(1) 28 | @thing.class.send(:define_method, :m3, &b2) 29 | lambda { @thing.method(:m3).to_source }.should.raise(error) 30 | end 31 | end 32 | 33 | describe 'w braced block' do 34 | should "raise #{error} w no nesting on same line" do 35 | b1 = lambda {|a| @x }; b2 = lambda { @x }; b3 = lambda { @x } 36 | @thing.class.send(:define_method, :m1, &b2) 37 | lambda { @thing.method(:m1).to_source }.should.raise(error) 38 | end 39 | 40 | should "raise #{error} w single level nesting on same line" do 41 | b1 = lambda {|a| @x }; b2 = lambda { lambda { @x } } 42 | @thing.class.send(:define_method, :m2, &b2) 43 | lambda { @thing.method(:m2).to_source }.should.raise(error) 44 | end 45 | 46 | should "raise #{error} w multi level nesting on same line" do 47 | b2 = (lambda {|a| lambda { lambda { @x } } }).call(1) 48 | @thing.class.send(:define_method, :m3, &b2) 49 | lambda { @thing.method(:m3).to_source }.should.raise(error) 50 | end 51 | end 52 | 53 | end 54 | 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/method/to_source_from_define_method_w_multi_blocks_and_single_match_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from define_method)' do 4 | describe 'w single blocks and many matches' do 5 | 6 | before { @thing = Object.new } 7 | 8 | describe 'w do...end block' do 9 | should 'skip non-matching w no nesting on same line' do 10 | b1 = lambda do |a| @x1 end; b2 = lambda do |b| @x2 end 11 | @thing.class.send(:define_method, :m1, &b2) 12 | @thing.method(:m1).should.be having_source(%( 13 | def m1(b) 14 | @x2 15 | end 16 | )) 17 | end 18 | 19 | should 'skip non-matching w single level nesting on same line' do 20 | b2 = (lambda do |a| lambda do |b| @x2 end end).call(1) 21 | @thing.class.send(:define_method, :m2, &b2) 22 | @thing.method(:m2).should.be having_source(%( 23 | def m2(b) 24 | @x2 25 | end 26 | )) 27 | end 28 | 29 | should 'skip non-matching w multi level nesting on same line' do 30 | b2 = (lambda do |a| lambda do |b| b2 = lambda do |c| @x3 end end end).call(1).call(1) 31 | @thing.class.send(:define_method, :m3, &b2) 32 | @thing.method(:m3).should.be having_source(%( 33 | def m3(c) 34 | @x3 35 | end 36 | )) 37 | end 38 | end 39 | 40 | describe 'w braced block' do 41 | should 'skip non-matching w no nesting on same line' do 42 | b1 = lambda {|a| @x1 }; b2 = lambda {|b| @x2 } 43 | @thing.class.send(:define_method, :m1, &b2) 44 | @thing.method(:m1).should.be having_source(%( 45 | def m1(b) 46 | @x2 47 | end 48 | )) 49 | end 50 | 51 | should 'skip non-matching w single level nesting on same line' do 52 | b2 = (lambda {|a| lambda {|b| @x2 } }).call(1) 53 | @thing.class.send(:define_method, :m2, &b2) 54 | @thing.method(:m2).should.be having_source(%( 55 | def m2(b) 56 | @x2 57 | end 58 | )) 59 | end 60 | 61 | should 'skip non-matching w multi level nesting on same line' do 62 | b2 = (lambda {|a| lambda {|b| b2 = lambda {|c| @x3 } } }).call(1).call(1) 63 | @thing.class.send(:define_method, :m3, &b2) 64 | @thing.method(:m3).should.be having_source(%( 65 | def m3(c) 66 | @x3 67 | end 68 | )) 69 | end 70 | end 71 | 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_many_matches_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from define_method)' do 4 | describe 'w specified {:attached_to => ...} & single match' do 5 | 6 | before { @thing = Object.new } 7 | options = {:attached_to => :lambda} 8 | 9 | if has_parsetree? 10 | # TODO: Should we support this ?? 11 | else 12 | 13 | error = Sourcify::MultipleMatchingProcsPerLineError 14 | 15 | should "raise #{error} w no nesting on same line" do 16 | b1 = lambda {|a| @x }; b2 = lambda { @x }; b3 = lambda { @x } 17 | @thing.class.send(:define_method, :m1, &b2) 18 | lambda { @thing.method(:m1).to_source(options) }.should.raise(error) 19 | end 20 | 21 | should "raise #{error} w single level nesting on same line" do 22 | b1 = lambda {|a| @x }; b2 = lambda { lambda { @x } } 23 | @thing.class.send(:define_method, :m2, &b2) 24 | lambda { @thing.method(:m2).to_source(options) }.should.raise(error) 25 | end 26 | 27 | should "raise #{error} w multi level nesting on same line" do 28 | b2 = (lambda {|a| lambda { lambda { @x } } }).call(1) 29 | @thing.class.send(:define_method, :m3, &b2) 30 | lambda { @thing.method(:m3).to_source(options) }.should.raise(error) 31 | end 32 | 33 | end 34 | 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_no_match_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from define_method)' do 4 | describe 'w specified {:attached_to => ...} & no match' do 5 | 6 | before { @thing = Object.new } 7 | options = {:attached_to => :forever} 8 | 9 | if has_parsetree? 10 | # TODO: Should we support this ?? 11 | else 12 | 13 | error = Sourcify::NoMatchingProcError 14 | 15 | should "raise #{error} w no nesting on same line" do 16 | b1 = lambda {|a| @x }; b2 = watever { @x }; b3 = lambda { @x } 17 | @thing.class.send(:define_method, :m1, &b2) 18 | lambda { @thing.method(:m1).to_source(options) }.should.raise(error) 19 | end 20 | 21 | should "raise #{error} w single level nesting on same line" do 22 | b1 = lambda {|a| @x }; b2 = watever { lambda { @x } } 23 | @thing.class.send(:define_method, :m2, &b2) 24 | lambda { @thing.method(:m2).to_source(options) }.should.raise(error) 25 | end 26 | 27 | should "raise #{error} w multi level nesting on same line" do 28 | b2 = (lambda {|a| watever { lambda { @x } } }).call(1) 29 | @thing.class.send(:define_method, :m3, &b2) 30 | lambda { @thing.method(:m3).to_source(options) }.should.raise(error) 31 | end 32 | 33 | end 34 | 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_single_match_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from define_method)' do 4 | describe 'w specified {:attached_to => ...} & single match' do 5 | 6 | before { @thing = Object.new } 7 | options = {:attached_to => :watever} 8 | 9 | should 'handle no nesting on same line' do 10 | b1 = lambda {|a| @x1+1 }; b2 = watever { @x1+2 }; b3 = lambda { @x1+3 } 11 | @thing.class.send(:define_method, :m1, &b2) 12 | @thing.method(:m1).should.be having_source('def m1; @x1+2; end', options) 13 | end 14 | 15 | should 'handle single level nesting on same line' do 16 | b1 = lambda {|a| @x2+1 }; b2 = watever { lambda { @x2+2 } } 17 | @thing.class.send(:define_method, :m2, &b2) 18 | @thing.method(:m2).should.be having_source('def m2; lambda { @x2+2 }; end', options) 19 | end 20 | 21 | should 'handle multi level nesting on same line' do 22 | b2 = (lambda {|a| watever { lambda { @x3 } } }).call(1) 23 | @thing.class.send(:define_method, :m3, &b2) 24 | @thing.method(:m3).should.be having_source('def m3; lambda { @x3 }; end', options) 25 | end 26 | 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/method/to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_many_matches_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from define_method)' do 4 | describe 'w specified body matcher & single match' do 5 | 6 | before { @thing = Object.new } 7 | matcher = lambda {|code| code =~ /^(.*\W|)alert\W/ } 8 | 9 | if has_parsetree? 10 | # TODO: Should we support this ?? 11 | else 12 | 13 | error = Sourcify::MultipleMatchingProcsPerLineError 14 | 15 | should "raise #{error} w no nesting on same line" do 16 | b1 = lambda {|a| @x }; b2 = lambda { alert(1) }; b3 = lambda { alert(2) } 17 | @thing.class.send(:define_method, :m1, &b2) 18 | lambda { @thing.method(:m1).to_source(&matcher) }.should.raise(error) 19 | end 20 | 21 | should "raise #{error} w single level nesting on same line" do 22 | b1 = lambda {|a| @x }; b2 = lambda { lambda { alert(1) } } 23 | @thing.class.send(:define_method, :m2, &b2) 24 | lambda { @thing.method(:m2).to_source(&matcher) }.should.raise(error) 25 | end 26 | 27 | should "raise #{error} w multi level nesting on same line" do 28 | b2 = (lambda {|a| lambda { lambda { alert(1) } } }).call(1) 29 | @thing.class.send(:define_method, :m3, &b2) 30 | lambda { @thing.method(:m3).to_source(&matcher) }.should.raise(error) 31 | end 32 | 33 | end 34 | 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/method/to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_no_match_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from define_method)' do 4 | describe 'w specified body matcher & no match' do 5 | 6 | before { @thing = Object.new } 7 | matcher = lambda {|code| code =~ /^(.*\W|)def\W/ } 8 | 9 | if has_parsetree? 10 | # TODO: Should we support this ?? 11 | else 12 | 13 | error = Sourcify::NoMatchingProcError 14 | 15 | should "raise #{error} w no nesting on same line" do 16 | b1 = lambda {|a| @x }; b2 = lambda { @x }; b3 = lambda { @x } 17 | @thing.class.send(:define_method, :m1, &b2) 18 | lambda { @thing.method(:m1).to_source(&matcher) }.should.raise(error) 19 | end 20 | 21 | should "raise #{error} w single level nesting on same line" do 22 | b1 = lambda {|a| @x }; b2 = lambda { lambda { @x } } 23 | @thing.class.send(:define_method, :m2, &b2) 24 | lambda { @thing.method(:m2).to_source(&matcher) }.should.raise(error) 25 | end 26 | 27 | should "raise #{error} w multi level nesting on same line" do 28 | b2 = (lambda {|a| lambda { lambda { @x } } }).call(1) 29 | @thing.class.send(:define_method, :m3, &b2) 30 | lambda { @thing.method(:m3).to_source(&matcher) }.should.raise(error) 31 | end 32 | 33 | end 34 | 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/method/to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_single_match_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from define_method)' do 4 | describe 'w specified body matcher & single match' do 5 | 6 | before { @thing = Object.new } 7 | matcher = lambda {|code| code =~ /^(.*\W|)alert\W/ } 8 | 9 | should 'handle no nesting on same line' do 10 | b1 = lambda {|a| @x1+1 }; b2 = lambda { @x1+2 }; b3 = lambda { alert(1) } 11 | @thing.class.send(:define_method, :m1, &b3) 12 | @thing.method(:m1).should.be having_source('def m1; alert(1); end', &matcher) 13 | end 14 | 15 | should 'handle single level nesting on same line' do 16 | b1 = lambda {|a| @x2+1 }; b2 = lambda { alert(1); lambda { @x2+3 } } 17 | @thing.class.send(:define_method, :m2, &b2) 18 | @thing.method(:m2).should.be having_source('def m2; alert(1); lambda { @x2+3 }; end', &matcher) 19 | end 20 | 21 | should 'handle multi level nesting on same line' do 22 | b2 = (lambda {|a| lambda { alert(1); lambda { @x3+3 } } }).call(1) 23 | @thing.class.send(:define_method, :m3, &b2) 24 | @thing.method(:m3).should.be having_source('def m3; alert(1); lambda { @x3+3 }; end', &matcher) 25 | end 26 | 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/method/to_source_from_define_method_w_multi_blocks_and_specified_ignore_nested_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source w specified {:ignore_nested => ...} (for defind_method)' do 4 | 5 | before { @thing = Object.new } 6 | options = {:ignore_nested => true} 7 | 8 | if has_parsetree? 9 | # TODO: Should we support parsetree ?? 10 | else 11 | 12 | should "raise Sourcify::MultipleMatchingProcsPerLineError w no nesting on same line" do 13 | b1 = lambda {|a| @x1+1 }; b2 = lambda { @x1+2 }; b3 = lambda { @x1+3 } 14 | @thing.class.send(:define_method, :m1, &b2) 15 | lambda { @thing.method(:m1).to_source(options) }.should.raise(Sourcify::MultipleMatchingProcsPerLineError) 16 | end 17 | 18 | should "handle w single level nesting on same line" do 19 | b1 = lambda {|a| @x2+1 }; b2 = lambda { lambda { @x2+3 } } 20 | @thing.class.send(:define_method, :m2, &b2) 21 | @thing.method(:m2).should.be having_source(%( 22 | def m2 23 | lambda { @x2+3 } 24 | end 25 | ), options) 26 | end 27 | 28 | should "raise Sourcify::NoMatchingProcError w multi level nesting on same line (w outermost having diff arity)" do 29 | b2 = (lambda {|a| lambda { lambda { @x3 } } }).call(1) 30 | @thing.class.send(:define_method, :m3, &b2) 31 | lambda { @thing.method(:m3).to_source(options) }.should.raise(Sourcify::NoMatchingProcError) 32 | end 33 | 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /spec/method/to_source_from_define_method_within_irb_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from define_method)' do 4 | describe 'within IRB' do 5 | 6 | class << self 7 | 8 | def irb_eval(string) 9 | irb_exec(string)[-1] 10 | end 11 | 12 | def equal_to(expected) 13 | lambda {|found| normalize_code(found) == normalize_code(expected) } 14 | end 15 | 16 | end 17 | 18 | should 'handle' do 19 | irb_eval(%\ 20 | thing = Object.new 21 | blk = lambda { x } 22 | thing.class.send(:define_method, :m1, &blk) 23 | thing.method(:m1).to_source 24 | \).should.be equal_to(%( 25 | def m1 26 | x 27 | end 28 | )) 29 | end 30 | 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/method/to_source_from_define_method_within_pry_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source (from define_method)' do 4 | describe 'within PRY' do 5 | 6 | class << self 7 | 8 | def pry_eval(string) 9 | pry_exec(string)[-1] 10 | end 11 | 12 | def equal_to(expected) 13 | lambda {|found| normalize_code(found) == normalize_code(expected) } 14 | end 15 | 16 | end 17 | 18 | should 'handle' do 19 | pry_eval(%\ 20 | thing = Object.new 21 | blk = lambda { x } 22 | thing.class.send(:define_method, :m1, &blk) 23 | thing.method(:m1).to_source 24 | \).should.be equal_to(%( 25 | def m1 26 | x 27 | end 28 | )) 29 | end 30 | 31 | should 'handle upward scroll' do 32 | pry_eval(%Q( 33 | thing = Object.new 34 | b1 = lambda { x1 } 35 | b2 = lambda { x2 } 36 | thing.class.send(:define_method, :m1, &b1) 37 | thing.class.send(:define_method, :m2, &b2) 38 | thing.method(:m1).to_source 39 | thing.method(:m2).to_source 40 |  41 | )).should.be equal_to(%( 42 | def m1 43 | x1 44 | end 45 | )) 46 | end 47 | 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/method/to_source_w_specified_strip_enclosure_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Method#to_source' do 4 | describe 'w specified {:strip_enclosure => ...}' do 5 | 6 | describe '>> w true' do 7 | 8 | options = {:strip_enclosure => true} 9 | 10 | should 'strip enclosing proc wo arg' do 11 | def m1; a+b; end 12 | method(:m1).should.be having_source(%(a + b), options) 13 | end 14 | 15 | should 'strip enclosing proc w arg' do 16 | def m2(a); a+b; end 17 | method(:m2).should.be having_source(%(a+b), options) 18 | end 19 | 20 | end 21 | 22 | describe '>> w false' do 23 | 24 | options = {:strip_enclosure => false} 25 | 26 | should 'not strip enclosing proc wo arg' do 27 | def m3; a+b; end 28 | method(:m3).should.be having_source(%(def m3; a+b; end), options) 29 | end 30 | 31 | should 'not strip enclosing proc w arg' do 32 | def m4(a); a+b; end 33 | method(:m4).should.be having_source(%(def m4(a); a+b; end), options) 34 | end 35 | 36 | end 37 | 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/no_method/unsupported_platform_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../spec_helper', __FILE__) 2 | 3 | describe "Unsupported Platform" do 4 | 5 | thing = Class.new do 6 | def self.echo 7 | end 8 | end 9 | 10 | should 'raise Sourcify::PlatformNotSupportedError when calling Method#to_source' do 11 | lambda{ thing.method(:echo).to_source }.should. 12 | raise(Sourcify::PlatformNotSupportedError) 13 | end 14 | 15 | should 'raise Sourcify::PlatformNotSupportedError when calling Method#to_sexp' do 16 | lambda{ thing.method(:echo).to_sexp }.should. 17 | raise(Sourcify::PlatformNotSupportedError) 18 | end 19 | 20 | should 'raise Sourcify::PlatformNotSupportedError when calling Method#to_raw_source' do 21 | lambda{ thing.method(:echo).to_raw_source }.should. 22 | raise(Sourcify::PlatformNotSupportedError) 23 | end 24 | 25 | end 26 | 27 | -------------------------------------------------------------------------------- /spec/proc/19x_extras.rb: -------------------------------------------------------------------------------- 1 | shared 'Proc#to_source from { ... } block (1.9.*)' do 2 | 3 | should 'handle simple (w label keys)' do 4 | ( 5 | lambda { 6 | {a: 1, b: 2} 7 | } 8 | ).should.be having_source(%Q\ 9 | proc do 10 | {:a => 1, :b => 2} 11 | end 12 | \) 13 | end 14 | 15 | should 'handle nested (w label keys)' do 16 | ( 17 | lambda { 18 | {a: 1, b: {c: 3}} 19 | } 20 | ).should.be having_source(%Q\ 21 | proc do 22 | {:a => 1, :b => {:c => 3}} 23 | end 24 | \) 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /spec/proc/created_on_the_fly_proc_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Created on the fly proc" do 4 | unless has_parsetree? 5 | 6 | klass = Class.new do 7 | def test(&block); block ; end 8 | def blah; 1+2; end 9 | end 10 | 11 | describe 'Blah#to_proc raising Sourcify::CannotHandleCreatedOnTheFlyProcError' do 12 | 13 | should "raise when created by :to_proc" do 14 | lambda { 15 | x, y = klass.new.method(:test).to_proc, lambda { 1+2 } 16 | x.to_source 17 | }.should.raise(Sourcify::CannotHandleCreatedOnTheFlyProcError) 18 | end 19 | 20 | should "not raise even with prepending #to_proc on the same line" do 21 | x, y = klass.new.method(:test).to_proc, lambda { 1+2 } 22 | y.to_source.should.not.be.nil 23 | end 24 | 25 | should "not raise even with appending #to_proc on the same line" do 26 | x, y = lambda { 1+2 }, klass.new.method(:test).to_proc 27 | x.to_source.should.not.be.nil 28 | end 29 | 30 | should "not raise even with nested #to_proc on the same line" do 31 | x = lambda { klass.new.method(:test).to_proc } 32 | x.to_source.should.not.be.nil 33 | end 34 | 35 | should "not raise with nested #to_proc on diff line" do 36 | ( 37 | lambda do 38 | klass.new.method(:test).to_proc 39 | end 40 | ).to_source.should.not.be.nil 41 | end 42 | 43 | end 44 | 45 | describe '&:blah raising Sourcify::CannotHandleCreatedOnTheFlyProcError' do 46 | 47 | should "raise when created by &:blah" do 48 | lambda { 49 | x, y = klass.new.test(&:blah), lambda { 1+2 } 50 | x.to_source 51 | }.should.raise(Sourcify::CannotHandleCreatedOnTheFlyProcError) 52 | end 53 | 54 | should "not raise even with prepending &:blah on the same line" do 55 | x, y = klass.new.test(&:blah), lambda { 1+2 } 56 | y.to_source.should.not.be.nil 57 | end 58 | 59 | should "not raise even with appending &:blah on the same line" do 60 | x, y = lambda { 1+2 }, klass.new.test(&:blah) 61 | x.to_source.should.not.be.nil 62 | end 63 | 64 | should "not raise even with nested &:blah on the same line" do 65 | x = lambda { klass.new.test(&:blah) } 66 | x.to_source.should.not.be.nil 67 | end 68 | 69 | should "not raise with nested &:blah on diff line" do 70 | ( 71 | lambda do 72 | klass.new.test(&:blah) 73 | end 74 | ).to_source.should.not.be.nil 75 | end 76 | 77 | end 78 | 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /spec/proc/encoding_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # NOTE: The examples in this file are adapted from the original pull 4 | # request submitted by tomykaira @ https://github.com/ngty/sourcify/pull/19. 5 | # 6 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 7 | 8 | describe "Encoding" do 9 | next unless Sourcify::IS_19x 10 | 11 | should "handle proc with UTF-8 string" do 12 | lambda { "こんにちは" }.should.be having_sexp( 13 | s(:iter, s(:call, nil, :proc, s(:arglist)), nil, s(:str, "こんにちは")) 14 | ) 15 | end 16 | 17 | should "handle proc with unicode regexp" do 18 | # NOTE: This specifically addresses https://github.com/ngty/sourcify/issues/15 19 | lambda { /\p{Lu}/ }.should.be having_sexp( 20 | s(:iter, s(:call, nil, :proc, s(:arglist)), nil, s(:lit, /\p{Lu}/)) 21 | ) 22 | end 23 | 24 | should "handle proc with UTF-8 heredoc" do 25 | ( 26 | lambda do 27 | <<-EOL 28 | こんにちは 29 | EOL 30 | end 31 | ).should.be having_sexp( 32 | s(:iter, s(:call, nil, :proc, s(:arglist)), nil, s(:str, " こんにちは\n")) 33 | ) 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /spec/proc/others_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Misc" do 4 | 5 | should 'handle accessing #to_sexp after #to_source' do 6 | (s_proc = lambda { :test }).to_source 7 | s_proc.should.be having_sexp(s(:iter, s(:call, nil, :proc, s(:arglist)), nil, s(:lit, :test))) 8 | end 9 | 10 | should 'handle accessing #to_source after #to_sexp' do 11 | (s_proc = lambda { :test }).to_sexp 12 | s_proc.should.be having_source('proc { :test }') 13 | end 14 | 15 | should "handle proc with '/' char" do 16 | (lambda { @x1/2 }).should.be having_source('proc { @x1/2 }') 17 | end 18 | 19 | should "handle lexer bug in missing trailing chars after '=>' operator" do 20 | # This example addresses bug @ http://redmine.ruby-lang.org/issues/show/3765 21 | { 22 | __LINE__ => lambda { :test } 23 | }.values.last.should.be having_source('proc { :test }') 24 | end 25 | 26 | should "handle lexer bug in missing trailing chars after '=>' operator" do 27 | # This example addresses bug @ http://redmine.ruby-lang.org/issues/show/3765 28 | { 29 | __LINE__ => lambda do :test end 30 | }.values.last.should.be having_source('proc { :test }') 31 | end 32 | 33 | unless has_parsetree? 34 | should "raise Sourcify::CannotParseEvalCodeError when proc is created from eval" do 35 | lambda { eval("proc {:test }").to_source }.should. 36 | raise(Sourcify::CannotParseEvalCodeError) 37 | end 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /spec/proc/raw_scanner/block_comment_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Proc's raw scanner > block comment (=begin ... =end)" do 5 | extend Sourcify::Proc::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Block comment (=begin ... =end)" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/proc/raw_scanner/double_colons_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Proc's raw scanner > double colons" do 5 | extend Sourcify::Proc::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Double colons" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/proc/raw_scanner/double_quote_str_w_interpolation_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Proc's raw scanner > double quote strings (w interpolation)" do 5 | extend Sourcify::Proc::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Double quote strings (w interpolation)" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/proc/raw_scanner/double_quote_str_wo_interpolation_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Proc's raw scanner > double quote strings (wo interpolation)" do 5 | extend Sourcify::Proc::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Double quote strings (wo interpolation)" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/proc/raw_scanner/heredoc_w_indent_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Proc's raw scanner > heredoc (w indent)" do 5 | extend Sourcify::Proc::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Heredoc (w indent)" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/proc/raw_scanner/heredoc_wo_indent_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Proc's raw scanner > heredoc (wo indent)" do 5 | extend Sourcify::Proc::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Heredoc (wo indent)" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/proc/raw_scanner/kw_block_start_alias1_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Proc's raw scanner > keyword block start alias #1 (incrementing counter by 1)" do 5 | 6 | extend Sourcify::Proc::Parser::RawScanner::Spec::KwBlockStartSupport 7 | behaves_like "Keyword block start alias #1 (incrementing counter by 1)" 8 | 9 | kw_block_start_alias1.each do |kw| 10 | should "increment counter with ... do #{kw} ..." do 11 | kw_block_start_counter(< keyword block start alias #2 (incrementing counter by 0..1)" do 5 | 6 | extend Sourcify::Proc::Parser::RawScanner::Spec::KwBlockStartSupport 7 | behaves_like "Keyword block start alias #2 (incrementing counter by 0..1)" 8 | 9 | kw_block_start_alias2.each do |kw| 10 | should "increment counter with ... do #{kw} ..." do 11 | kw_block_start_counter(< per line comment (# ...)" do 5 | extend Sourcify::Proc::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like "Per line comment (# ...)" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/proc/raw_scanner/single_quote_str_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Proc's raw scanner > single quote strings (\', %q & %w)" do 5 | extend Sourcify::Proc::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like 'Single quote strings (\', %q & %w)' 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/proc/raw_scanner/slash_operator_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../spec_helper', __FILE__) 2 | 3 | unless has_parsetree? 4 | describe "Proc's raw scanner > slash operator" do 5 | extend Sourcify::Proc::Parser::RawScanner::Spec::GenericSupport 6 | behaves_like 'Slash operator' 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/proc/raw_scanner/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../../spec_helper', __FILE__) 2 | require File.expand_path('../../../raw_scanner/shared_specs', __FILE__) 3 | 4 | module Sourcify::Proc::Parser::RawScanner 5 | 6 | SCANNER = self 7 | 8 | class << self 9 | attr_reader :tokens, :do_end_counter 10 | end 11 | 12 | module Spec 13 | 14 | module GenericSupport 15 | def self.extended(base) 16 | base.instance_eval do 17 | def process(data) 18 | SCANNER.process(data) 19 | SCANNER.tokens 20 | end 21 | end 22 | end 23 | end 24 | 25 | module KwBlockStartSupport 26 | def self.extended(base) 27 | base.instance_eval do 28 | 29 | before do 30 | counter(:DoEndBlockCounter).class_eval do 31 | alias_method :orig_started?, :started? 32 | def started?; true; end 33 | end 34 | end 35 | 36 | after do 37 | counter(:DoEndBlockCounter).class_eval do 38 | alias_method :started?, :orig_started? 39 | end 40 | end 41 | 42 | def counter(type) 43 | Sourcify::Proc::Parser::RawScanner::Extensions.const_get(type) 44 | end 45 | 46 | def kw_block_start_counter(data) 47 | SCANNER.process(data) 48 | SCANNER.do_end_counter.counts 49 | end 50 | 51 | def kw_block_start_alias1 52 | %w{class def module begin case module if unless} 53 | end 54 | 55 | def kw_block_start_alias2 56 | %w{while until for} 57 | end 58 | end 59 | end 60 | end 61 | 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/proc/readme: -------------------------------------------------------------------------------- 1 | Since Proc#to_source depends on Proc#to_sexp, getting Proc#to_source correct 2 | implies the correctness of Proc#to_sexp, thus, there is no need to maintain 3 | 2 sets of almost similar specs ... the only spec worth maintaining separately 4 | is the one for variables, since we are concerned with whether the correct 5 | representation of sexp is there. 6 | -------------------------------------------------------------------------------- /spec/proc/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'spec_helper') 2 | -------------------------------------------------------------------------------- /spec/proc/to_raw_source_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_raw_source" do 4 | 5 | should 'retain comments' do 6 | ( 7 | lambda do 8 | a = 1 9 | # i should stay !! 10 | end 11 | ).should.be having_raw_source(%( 12 | proc do 13 | a = 1 14 | # i should stay !! 15 | end 16 | )) 17 | end 18 | 19 | should 'retain last nil statement' do 20 | ( 21 | lambda do 22 | a = 1 23 | nil 24 | end 25 | ).should.be having_raw_source(%( 26 | proc do 27 | a = 1 28 | nil 29 | end 30 | )) 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /spec/proc/to_raw_source_w_specified_strip_enclosure_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_raw_source w specified {:strip_enclosure => ...}' do 4 | 5 | describe '>> w true' do 6 | 7 | options = {:strip_enclosure => true} 8 | 9 | should 'strip enclosing proc wo arg' do 10 | ( 11 | lambda do 12 | a = 1 13 | # i should stay !! 14 | end 15 | ).should.be having_raw_source(%( 16 | a = 1 17 | # i should stay !! 18 | ), options) 19 | end 20 | 21 | should 'strip enclosing proc w arg' do 22 | ( 23 | lambda do |a| 24 | a = 1 25 | # i should stay !! 26 | end 27 | ).should.be having_raw_source(%( 28 | a = 1 29 | # i should stay !! 30 | ), options) 31 | end 32 | 33 | end 34 | 35 | describe '>> w false' do 36 | 37 | options = {:strip_enclosure => false} 38 | 39 | should 'not strip enclosing proc wo arg' do 40 | ( 41 | lambda do 42 | a = 1 43 | # i should stay !! 44 | end 45 | ).should.be having_raw_source(%( 46 | proc do 47 | a = 1 48 | # i should stay !! 49 | end 50 | ), options) 51 | end 52 | 53 | should 'not strip enclosing proc w arg' do 54 | ( 55 | lambda do |a| 56 | a = 1 57 | # i should stay !! 58 | end 59 | ).should.be having_raw_source(%( 60 | proc do |a| 61 | a = 1 62 | # i should stay !! 63 | end 64 | ), options) 65 | end 66 | 67 | end 68 | 69 | end 70 | -------------------------------------------------------------------------------- /spec/proc/to_sexp_from_multi_blocks_w_specified_attached_to_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_sexp w specified {:attached_to => ...}' do 4 | 5 | # NOTE: We just want enough specs to show that handling of :attached_to 6 | # works for Proc#to_sexp as well. 7 | 8 | options = {:attached_to => /^.*?(\W|)watever(\W)/} 9 | 10 | should 'handle no nesting on same line' do 11 | b1 = lambda {|a| @x1+1 }; b2 = watever { @x1+2 }; b3 = lambda { @x1+3 } 12 | b2.should.be having_sexp( 13 | s(:iter, 14 | s(:call, nil, :proc, s(:arglist)), 15 | nil, 16 | s(:call, s(:ivar, :@x1), :+, s(:arglist, s(:lit, 2)))), 17 | options 18 | ) 19 | end 20 | 21 | should 'handle single level nesting on same line' do 22 | b1 = lambda {|a| @x2+1 }; b2 = watever { lambda { @x2+2 } } 23 | b2.should.be having_sexp( 24 | s(:iter, 25 | s(:call, nil, :proc, s(:arglist)), 26 | nil, 27 | s(:iter, 28 | s(:call, nil, :lambda, s(:arglist)), 29 | nil, 30 | s(:call, s(:ivar, :@x2), :+, s(:arglist, s(:lit, 2))))), 31 | options 32 | ) 33 | end 34 | 35 | should 'handle multi level nesting on same line' do 36 | b2 = (lambda {|a| watever { lambda { @x3 } } }).call(1) 37 | b2.should.be having_sexp( 38 | s(:iter, 39 | s(:call, nil, :proc, s(:arglist)), 40 | nil, 41 | s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:ivar, :@x3))), 42 | options 43 | ) 44 | end 45 | 46 | end 47 | -------------------------------------------------------------------------------- /spec/proc/to_sexp_w_specified_strip_enclosure_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_sexp w specified {:strip_enclosure => ...}' do 4 | 5 | describe '>> w true' do 6 | 7 | options = {:strip_enclosure => true} 8 | 9 | should 'strip enclosing proc wo arg' do 10 | lambda { a+b }.should.be having_sexp( 11 | s(:call, 12 | s(:call, nil, :a, s(:arglist)), 13 | :+, 14 | s(:arglist, s(:call, nil, :b, s(:arglist)))), 15 | options 16 | ) 17 | end 18 | 19 | should 'strip enclosing proc w arg' do 20 | lambda {|a| a+b }.should.be having_sexp( 21 | s(:call, 22 | s(:lvar, :a), 23 | :+, 24 | s(:arglist, s(:call, nil, :b, s(:arglist)))), 25 | options 26 | ) 27 | end 28 | 29 | end 30 | 31 | describe '>> w false' do 32 | 33 | options = {:strip_enclosure => false} 34 | 35 | should 'not strip enclosing proc wo arg' do 36 | lambda { a+b }.should.be having_sexp( 37 | s(:iter, 38 | s(:call, nil, :proc, s(:arglist)), 39 | nil, 40 | s(:call, 41 | s(:call, nil, :a, s(:arglist)), 42 | :+, 43 | s(:arglist, s(:call, nil, :b, s(:arglist))))), 44 | options 45 | ) 46 | end 47 | 48 | should 'not strip enclosing proc w arg' do 49 | lambda {|a| a+b }.should.be having_sexp( 50 | s(:iter, 51 | s(:call, nil, :proc, s(:arglist)), 52 | s(:lasgn, :a), 53 | s(:call, s(:lvar, :a), :+, s(:arglist, s(:call, nil, :b, s(:arglist))))), 54 | options 55 | ) 56 | end 57 | 58 | end 59 | 60 | end 61 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_braced_block_w_nested_braced_block_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from { ... } block (w nested { ... } block)" do 4 | 5 | should 'handle simple' do 6 | ( 7 | lambda { 8 | lambda { @x1 = 1 } 9 | } 10 | ).should.be having_source(%Q\ 11 | proc do 12 | lambda { @x1 = 1 } 13 | end 14 | \) 15 | end 16 | 17 | should 'handle nested' do 18 | ( 19 | lambda { 20 | lambda { 21 | lambda { @x1 = 1 } 22 | } 23 | } 24 | ).should.be having_source(%Q\ 25 | proc do 26 | lambda do 27 | lambda { @x1 = 1 } 28 | end 29 | end 30 | \) 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_braced_block_w_nested_hash_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from { ... } block (w nested hash)" do 4 | 5 | should 'handle simple' do 6 | ( 7 | lambda { 8 | {:a => 1, :b => 2} 9 | } 10 | ).should.be having_source(%Q\ 11 | proc do 12 | {:a => 1, :b => 2} 13 | end 14 | \) 15 | end 16 | 17 | should 'handle nested' do 18 | ( 19 | lambda { 20 | {:a => 1, :b => {:c => 3}} 21 | } 22 | ).should.be having_source(%Q\ 23 | proc do 24 | {:a => 1, :b => {:c => 3}} 25 | end 26 | \) 27 | end 28 | 29 | should 'handle method w only hash args (wo parens)' do 30 | ( 31 | lambda { 32 | test :a => 2 33 | } 34 | ).should.be having_source(%Q\ 35 | proc do 36 | test(:a => 2) 37 | end 38 | \) 39 | end 40 | 41 | should 'handle method w only hash args (w parens)' do 42 | ( 43 | lambda { 44 | test(:a => 2) 45 | } 46 | ).should.be having_source(%Q\ 47 | proc do 48 | test(:a => 2) 49 | end 50 | \) 51 | end 52 | 53 | should 'handle method w mixed args (wo parens)' do 54 | ( 55 | lambda { 56 | test 1, :a => 2 57 | } 58 | ).should.be having_source(%Q\ 59 | proc do 60 | test(1, :a => 2) 61 | end 62 | \) 63 | end 64 | 65 | should 'handle method w mixed args (w parens)' do 66 | ( 67 | lambda { 68 | test(1, :a => 2) 69 | } 70 | ).should.be having_source(%Q\ 71 | proc do 72 | test(1, :a => 2) 73 | end 74 | \) 75 | end 76 | 77 | if RUBY_VERSION.include?('1.9.') 78 | require File.join(File.expand_path(File.dirname(__FILE__)), '19x_extras') 79 | behaves_like 'Proc#to_source from { ... } block (1.9.*)' 80 | end 81 | 82 | end 83 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_braced_block_wo_nesting_complication_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from { ... } block (wo nesting complication)" do 4 | 5 | expected = 'proc { @x%s }' 6 | 7 | should 'handle watever(..) { ... }' do 8 | ( 9 | watever(:a, :b, {:c => 1}) { @x1 } 10 | ).should.be having_source(expected%1) 11 | end 12 | 13 | should 'handle watever(..) \ { ... }' do 14 | ( 15 | watever(:a, :b, {:c => 1}) \ 16 | { @x2 } 17 | ).should.be having_source(expected%2) 18 | end 19 | 20 | should 'handle watever { ... }' do 21 | ( 22 | watever { @x3 } 23 | ).should.be having_source(expected%3) 24 | end 25 | 26 | should 'handle watever \ { ... }' do 27 | ( 28 | watever \ 29 | { @x4 } 30 | ).should.be having_source(expected%4) 31 | end 32 | 33 | should 'handle lambda { ... }' do 34 | ( 35 | lambda { @x5 } 36 | ).should.be having_source(expected%5) 37 | end 38 | 39 | should 'handle lambda \ { ... }' do 40 | ( 41 | lambda \ 42 | { @x6 } 43 | ).should.be having_source(expected%6) 44 | end 45 | 46 | end 47 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_do_end_block_w_nested_begin_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from do ... end block (w nested begin)" do 4 | 5 | should 'handle simple' do 6 | ( 7 | lambda do 8 | begin @x1 = 1 end 9 | end 10 | ).should.be having_source(%Q\ 11 | proc do 12 | begin @x1 = 1 end 13 | end 14 | \) 15 | end 16 | 17 | should 'handle nested' do 18 | ( 19 | lambda do 20 | begin 21 | @x1 = 1 22 | begin @x2 = 2 end 23 | end 24 | end 25 | ).should.be having_source(%Q\ 26 | proc do 27 | begin 28 | @x1 = 1 29 | begin @x2 = 2 end 30 | end 31 | end 32 | \) 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_do_end_block_w_nested_case_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from do ... end block (w nested case)" do 4 | 5 | should 'handle simple' do 6 | ( 7 | lambda do 8 | case @x1 when true then false end 9 | end 10 | ).should.be having_source(%Q\ 11 | proc do 12 | case @x1 when true then false end 13 | end 14 | \) 15 | end 16 | 17 | should 'handle nested' do 18 | ( 19 | lambda do 20 | case @x1 21 | when true 22 | case @x2 when false then true end 23 | end 24 | end 25 | ).should.be having_source(%Q\ 26 | proc do 27 | case @x1 28 | when true 29 | case @x2 when false then true end 30 | end 31 | end 32 | \) 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_do_end_block_w_nested_class_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from do ... end block (w nested class)" do 4 | 5 | should 'handle simple' do 6 | ( 7 | lambda do 8 | class AA 9 | def aa 10 | @x1 = 1 11 | end 12 | end 13 | end 14 | ).should.be having_source(%Q\ 15 | proc do 16 | class AA 17 | def aa 18 | @x1 = 1 19 | end 20 | end 21 | end 22 | \) 23 | end 24 | 25 | should 'handle inheritance' do 26 | ( 27 | lambda do 28 | class AA < Object 29 | def aa 30 | @x1 = 1 31 | end 32 | end 33 | end 34 | ).should.be having_source(%Q\ 35 | proc do 36 | class AA < Object 37 | def aa 38 | @x1 = 1 39 | end 40 | end 41 | end 42 | \) 43 | end 44 | 45 | should 'handle singleton' do 46 | ( 47 | lambda do 48 | class << 'AA' 49 | def aa 50 | @x1 = 1 51 | end 52 | end 53 | end 54 | ).should.be having_source(%Q\ 55 | proc do 56 | class << 'AA' 57 | def aa 58 | @x1 = 1 59 | end 60 | end 61 | end 62 | \) 63 | end 64 | 65 | should 'handle nested' do 66 | ( 67 | lambda do 68 | class AA 69 | class BB 70 | def bb 71 | @x1 = 1 72 | end 73 | end 74 | end 75 | end 76 | ).should.be having_source(%Q\ 77 | proc do 78 | class AA 79 | class BB 80 | def bb 81 | @x1 = 1 82 | end 83 | end 84 | end 85 | end 86 | \) 87 | end 88 | 89 | end 90 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_do_end_block_w_nested_do_end_block_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from do ... end block (w nested do ... end block)" do 4 | 5 | should 'handle simple' do 6 | ( 7 | lambda do 8 | lambda do @x1 = 1 end 9 | end 10 | ).should.be having_source(%Q\ 11 | proc do 12 | lambda { @x1 = 1 } 13 | end 14 | \) 15 | end 16 | 17 | should 'handle nested' do 18 | ( 19 | lambda do 20 | lambda do 21 | lambda do @x1 = 1 end 22 | end 23 | end 24 | ).should.be having_source(%Q\ 25 | proc do 26 | lambda do 27 | lambda { @x1 = 1 } 28 | end 29 | end 30 | \) 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_do_end_block_w_nested_for_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from do ... end block (w nested for block)" do 4 | 5 | should 'handle w do' do 6 | ( 7 | lambda do 8 | for x1 in [1,2] do x1 end 9 | end 10 | ).should.be having_source(%Q\ 11 | proc do 12 | for x1 in [1,2] do x1 end 13 | end 14 | \) 15 | end 16 | 17 | should 'handle w \ do' do 18 | ( 19 | lambda do 20 | for x2 in [1,2] \ 21 | do x2 end 22 | end 23 | ).should.be having_source(%Q\ 24 | proc do 25 | for x2 in [1,2] do x2 end 26 | end 27 | \) 28 | end 29 | 30 | should 'handle wo do (w newline)' do 31 | ( 32 | lambda do 33 | for x3 in [1,2] 34 | x3 35 | end 36 | end 37 | ).should.be having_source(%Q\ 38 | proc do 39 | for x3 in [1,2] 40 | x3 41 | end 42 | end 43 | \) 44 | end 45 | 46 | should 'handle wo do (w semicolon)' do 47 | ( 48 | lambda do 49 | for x4 in [1,2]; x4; end 50 | end 51 | ).should.be having_source(%Q\ 52 | proc do 53 | for x4 in [1,2] 54 | x4 55 | end 56 | end 57 | \) 58 | end 59 | 60 | should 'handle nested wo do within w do' do 61 | ( 62 | lambda do 63 | for x1 in [1,2] do 64 | for x2 in [1,2] 65 | x2 66 | end 67 | end 68 | end 69 | ).should.be having_source(%Q\ 70 | proc do 71 | for x1 in [1,2] do 72 | for x2 in [1,2] 73 | x2 74 | end 75 | end 76 | end 77 | \) 78 | end 79 | 80 | should 'handle nested wo do within wo do' do 81 | ( 82 | lambda do 83 | for x1 in [2,3] 84 | for x2 in [2,3] 85 | x2 86 | end 87 | end 88 | end 89 | ).should.be having_source(%Q\ 90 | proc do 91 | for x1 in [2,3] do 92 | for x2 in [2,3] 93 | x2 94 | end 95 | end 96 | end 97 | \) 98 | end 99 | 100 | should 'handle nested w do within wo do' do 101 | ( 102 | lambda do 103 | for x1 in [3,4] 104 | for x2 in [3,4] do x2 end 105 | end 106 | end 107 | ).should.be having_source(%Q\ 108 | proc do 109 | for x1 in [3,4] 110 | for x2 in [3,4] do x2 end 111 | end 112 | end 113 | \) 114 | end 115 | 116 | should 'handle nested w do within w do' do 117 | ( 118 | lambda do 119 | for x1 in [4,5] \ 120 | do for x2 in [4,5] do x2 end 121 | end 122 | end 123 | ).should.be having_source(%Q\ 124 | proc do 125 | for x1 in [4,5] 126 | for x2 in [4,5] do x2 end 127 | end 128 | end 129 | \) 130 | end 131 | 132 | end 133 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_do_end_block_w_nested_if_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from do ... end block (w nested if)" do 4 | 5 | should 'handle simple block' do 6 | ( 7 | lambda do 8 | if @x1 then @x1 = 1 end 9 | end 10 | ).should.be having_source(%Q\ 11 | proc do 12 | if @x1 then @x1 = 1 end 13 | end 14 | \) 15 | end 16 | 17 | should 'handle nested block' do 18 | ( 19 | lambda do 20 | if @x1 21 | if @x2 then @x2 = 1 end 22 | end 23 | end 24 | ).should.be having_source(%Q\ 25 | proc do 26 | if @x1 27 | if @x2 then @x2 = 1 end 28 | end 29 | end 30 | \) 31 | end 32 | 33 | should 'handle simple modifier' do 34 | ( 35 | lambda do 36 | @x1 = 1 if true 37 | end 38 | ).should.be having_source(%Q\ 39 | proc do 40 | @x1 = 1 if true 41 | end 42 | \) 43 | end 44 | 45 | # NOTE: Syntatically correct, but the RubyParser-2.3.* can't handle it. 46 | # should 'handle block within modifier' do 47 | # ( 48 | # lambda do 49 | # @x1 = 1 if (if @x1 then true end) 50 | # end 51 | # ).should.be having_source(%Q\ 52 | # proc do 53 | # @x1 = 1 if (if @x1 then true end) 54 | # end 55 | # \) 56 | # end 57 | 58 | should 'handle modifier w trailing backslash' do 59 | ( 60 | lambda do 61 | @x1 = 1 \ 62 | if true 63 | end 64 | ).should.be having_source(%Q\ 65 | proc do 66 | @x1 = 1 if true 67 | end 68 | \) 69 | end 70 | 71 | should 'handle modifier within block' do 72 | ( 73 | lambda do 74 | if @x1 75 | @x1 = 1 if @x2 76 | end 77 | end 78 | ).should.be having_source(%Q\ 79 | proc do 80 | if @x1 81 | @x1 = 1 if @x2 82 | end 83 | end 84 | \) 85 | end 86 | 87 | end 88 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_do_end_block_w_nested_literal_keyword_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from do ... end block (w nested literal keyword)" do 4 | 5 | # See http://redmine.ruby-lang.org/issues/show/3764 6 | 7 | should 'handle :class' do 8 | ( 9 | lambda do 10 | x = :class 11 | end 12 | ).should.be having_source('proc { x = :class }') 13 | end 14 | 15 | should 'handle :module' do 16 | ( 17 | lambda do 18 | x = :module 19 | end 20 | ).should.be having_source('proc { x = :module }') 21 | end 22 | 23 | should 'handle :def' do 24 | ( 25 | lambda do 26 | x = :def 27 | end 28 | ).should.be having_source('proc { x = :def }') 29 | end 30 | 31 | should 'handle :if' do 32 | ( 33 | lambda do 34 | x = :if 35 | end 36 | ).should.be having_source('proc { x = :if }') 37 | end 38 | 39 | should 'handle :unless' do 40 | ( 41 | lambda do 42 | x = :unless 43 | end 44 | ).should.be having_source('proc { x = :unless }') 45 | end 46 | 47 | should 'handle :for' do 48 | ( 49 | lambda do 50 | x = :for 51 | end 52 | ).should.be having_source('proc { x = :for }') 53 | end 54 | 55 | should 'handle :while' do 56 | ( 57 | lambda do 58 | x = :while 59 | end 60 | ).should.be having_source('proc { x = :while }') 61 | end 62 | 63 | should 'handle :until' do 64 | ( 65 | lambda do 66 | x = :until 67 | end 68 | ).should.be having_source('proc { x = :until }') 69 | end 70 | 71 | should 'handle :begin' do 72 | ( 73 | lambda do 74 | x = :begin 75 | end 76 | ).should.be having_source('proc { x = :begin }') 77 | end 78 | 79 | should 'handle :case' do 80 | ( 81 | lambda do 82 | x = :case 83 | end 84 | ).should.be having_source('proc { x = :case }') 85 | end 86 | 87 | should 'handle :do' do 88 | ( 89 | lambda do 90 | x = :do 91 | end 92 | ).should.be having_source('proc { x = :do }') 93 | end 94 | 95 | should 'handle :end' do 96 | ( 97 | lambda do 98 | x = :end 99 | end 100 | ).should.be having_source('proc { x = :end }') 101 | end 102 | 103 | end 104 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_do_end_block_w_nested_method_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from do ... end block (w nested method)" do 4 | 5 | should 'handle simple' do 6 | ( 7 | lambda do 8 | def aa; x = 1; end 9 | end 10 | ).should.be having_source(%Q\ 11 | proc do 12 | def aa; x = 1; end 13 | end 14 | \) 15 | end 16 | 17 | should 'handle nested' do 18 | ( 19 | lambda do 20 | def aa 21 | def bb; x = 2; end 22 | end 23 | end 24 | ).should.be having_source(%Q\ 25 | proc do 26 | def aa 27 | def bb; x = 2; end 28 | end 29 | end 30 | \) 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_do_end_block_w_nested_module_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from do ... end block (w nested module)" do 4 | 5 | should 'handle simple' do 6 | ( 7 | lambda do 8 | module AA 9 | def aa 10 | @x1 = 1 11 | end 12 | end 13 | end 14 | ).should.be having_source(%Q\ 15 | proc do 16 | module AA 17 | def aa 18 | @x1 = 1 19 | end 20 | end 21 | end 22 | \) 23 | end 24 | 25 | should 'handle nested' do 26 | ( 27 | lambda do 28 | module AA 29 | module BB 30 | def bb 31 | @x1 = 1 32 | end 33 | end 34 | end 35 | end 36 | ).should.be having_source(%Q\ 37 | proc do 38 | module AA 39 | module BB 40 | def bb 41 | @x1 = 1 42 | end 43 | end 44 | end 45 | end 46 | \) 47 | end 48 | 49 | end 50 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_do_end_block_w_nested_unless_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from do ... end block (w nested unless)" do 4 | 5 | should 'handle simple block' do 6 | ( 7 | lambda do 8 | unless @x1 then @x1 = 1 end 9 | end 10 | ).should.be having_source(%Q\ 11 | proc do 12 | unless @x1 then @x1 = 1 end 13 | end 14 | \) 15 | end 16 | 17 | should 'handle nested block' do 18 | ( 19 | lambda do 20 | unless @x1 21 | unless @x2 then @x2 = 1 end 22 | end 23 | end 24 | ).should.be having_source(%Q\ 25 | proc do 26 | unless @x1 27 | unless @x2 then @x2 = 1 end 28 | end 29 | end 30 | \) 31 | end 32 | 33 | should 'handle simple modifier' do 34 | ( 35 | lambda do 36 | @x1 = 1 unless true 37 | end 38 | ).should.be having_source(%Q\ 39 | proc do 40 | @x1 = 1 unless true 41 | end 42 | \) 43 | end 44 | 45 | # NOTE: Syntatically correct, but the RubyParser-2.3.* can't handle it. 46 | # should 'handle block within modifier' do 47 | # ( 48 | # lambda do 49 | # @x1 = 1 unless (unless @x1 then true end) 50 | # end 51 | # ).should.be having_source(%Q\ 52 | # proc do 53 | # @x1 = 1 unless (unless @x1 then true end) 54 | # end 55 | # \) 56 | # end 57 | 58 | should 'handle modifier within block' do 59 | ( 60 | lambda do 61 | unless @x1 62 | @x1 = 1 unless @x2 63 | end 64 | end 65 | ).should.be having_source(%Q\ 66 | proc do 67 | unless @x1 68 | @x1 = 1 unless @x2 69 | end 70 | end 71 | \) 72 | end 73 | 74 | should 'handle modifier w trailing backslash' do 75 | ( 76 | lambda do 77 | @x1 = 1 \ 78 | unless true 79 | end 80 | ).should.be having_source(%Q\ 81 | proc do 82 | @x1 = 1 unless true 83 | end 84 | \) 85 | end 86 | 87 | end 88 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_do_end_block_wo_nesting_complication_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source from do ... end block (wo nesting complication)" do 4 | 5 | expected = 'proc { @x%s }' 6 | 7 | should 'handle watever(..) do ... end' do 8 | ( 9 | watever(:a, :b, {:c => 1}) do @x1 end 10 | ).should.be having_source(expected%1) 11 | end 12 | 13 | should 'handle watever(..) \ do ... end' do 14 | ( 15 | watever(:a, :b, {:c => 1}) \ 16 | do @x2 end 17 | ).should.be having_source(expected%2) 18 | end 19 | 20 | should 'handle watever do ... end' do 21 | ( 22 | watever do @x3 end 23 | ).should.be having_source(expected%3) 24 | end 25 | 26 | should 'handle watever \ do ... end' do 27 | ( 28 | watever \ 29 | do @x4 end 30 | ).should.be having_source(expected%4) 31 | end 32 | 33 | should 'handle lambda do ... end' do 34 | ( 35 | lambda do @x5 end 36 | ).should.be having_source(expected%5) 37 | end 38 | 39 | should 'handle lambda \ do ... end' do 40 | ( 41 | lambda \ 42 | do @x6 end 43 | ).should.be having_source(expected%6) 44 | end 45 | 46 | end 47 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_multi_blocks_w_many_matches_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_source from multi blocks w many matches' do 4 | 5 | if has_parsetree? 6 | 7 | should "handle w no nesting on same line" do 8 | b1 = lambda {|a| @x1+1 }; b2 = lambda { @x1+2 }; b3 = lambda { @x1+3 } 9 | b2.should.be having_source('proc { @x1+2 }') 10 | end 11 | 12 | should "handle w single level nesting on same line" do 13 | b1 = lambda {|a| @x2+1 }; b2 = lambda { lambda { @x2+2 } } 14 | b2.should.be having_source('proc { lambda { @x2+2 } }') 15 | end 16 | 17 | should "handle w multi level nesting on same line" do 18 | b2 = (lambda {|a| lambda { lambda { @x3 } } }).call(1) 19 | b2.should.be having_source('proc { lambda { @x3 } }') 20 | end 21 | 22 | else 23 | 24 | error = Sourcify::MultipleMatchingProcsPerLineError 25 | 26 | should "raise #{error} w no nesting on same line" do 27 | b1 = lambda {|a| @x }; b2 = lambda { @x }; b3 = lambda { @x } 28 | lambda { b2.to_source }.should.raise(error) 29 | end 30 | 31 | should "raise #{error} w single level nesting on same line" do 32 | b1 = lambda {|a| @x }; b2 = lambda { lambda { @x } } 33 | lambda { b2.to_source }.should.raise(error) 34 | end 35 | 36 | should "raise #{error} w multi level nesting on same line" do 37 | b2 = (lambda {|a| lambda { lambda { @x } } }).call(1) 38 | lambda { b2.to_source }.should.raise(error) 39 | end 40 | 41 | end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_multi_blocks_w_single_match_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_source from multi blocks w single match' do 4 | 5 | should 'skip non-matching w no nesting on same line' do 6 | b1 = lambda do |a| @x1 end; b2 = lambda do @x1 end 7 | b2.should.be having_source('proc { @x1 }') 8 | end 9 | 10 | should 'skip non-matching w single level nesting on same line' do 11 | b2 = (lambda {|a| lambda { @x2 } }).call(1) 12 | b2.should.be having_source('proc { @x2 }') 13 | end 14 | 15 | should 'skip non-matching w multi level nesting on same line' do 16 | b2 = (lambda {|a| lambda {|a| b2 = lambda { @x3 } } }).call(1).call(1) 17 | b2.should.be having_source('proc { @x3 }') 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_multi_blocks_w_specified_attached_to_and_many_matches_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_source w specified {:attached_to => ...} & single match' do 4 | 5 | options = {:attached_to => :lambda} 6 | 7 | if has_parsetree? 8 | 9 | should 'handle no nesting on same line' do 10 | b1 = lambda {|a| @x1+1 }; b2 = lambda { @x1+2 }; b3 = lambda { @x1+3 } 11 | b2.should.be having_source('proc { @x1+2 }', options) 12 | end 13 | 14 | should 'handle single level nesting on same line' do 15 | b1 = lambda {|a| @x2+1 }; b2 = lambda { lambda { @x2+2 } } 16 | b2.should.be having_source('proc { lambda { @x2+2 } }', options) 17 | end 18 | 19 | should 'handle multi level nesting on same line' do 20 | b2 = (lambda {|a| lambda { lambda { @x3 } } }).call(1) 21 | b2.should.be having_source('proc { lambda { @x3 } }', options) 22 | end 23 | 24 | else 25 | 26 | error = Sourcify::MultipleMatchingProcsPerLineError 27 | 28 | should "raise #{error} w no nesting on same line" do 29 | b1 = lambda {|a| @x }; b2 = lambda { @x }; b3 = lambda { @x } 30 | lambda { b2.to_source(options) }.should.raise(error) 31 | end 32 | 33 | should "raise #{error} w single level nesting on same line" do 34 | b1 = lambda {|a| @x }; b2 = lambda { lambda { @x } } 35 | lambda { b2.to_source(options) }.should.raise(error) 36 | end 37 | 38 | should "raise #{error} w multi level nesting on same line" do 39 | b2 = (lambda {|a| lambda { lambda { @x } } }).call(1) 40 | lambda { b2.to_source(options) }.should.raise(error) 41 | end 42 | 43 | end 44 | 45 | end 46 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_multi_blocks_w_specified_attached_to_and_no_match_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_source w specified {:attached_to => ...} & no match' do 4 | 5 | options = {:attached_to => :forever} 6 | 7 | if has_parsetree? 8 | 9 | should 'handle no nesting on same line' do 10 | b1 = lambda do |a| @x1+1 end; b2 = lambda do @x1+2 end; b3 = lambda do @x1+3 end 11 | b2.should.be having_source('proc { @x1+2 }', options) 12 | end 13 | 14 | should 'handle single level nesting on same line' do 15 | b1 = lambda do |a| @x2+1 end; b2 = lambda do lambda do @x2+2 end end 16 | b2.should.be having_source('proc { lambda { @x2+2 } }', options) 17 | end 18 | 19 | should 'handle multi level nesting on same line' do 20 | b2 = (lambda do |a| lambda do lambda do @x3 end end end).call(1) 21 | b2.should.be having_source('proc { lambda { @x3 } }', options) 22 | end 23 | 24 | else 25 | 26 | error = Sourcify::NoMatchingProcError 27 | 28 | should "raise #{error} w no nesting on same line" do 29 | b1 = lambda {|a| @x }; b2 = watever { @x }; b3 = lambda { @x } 30 | lambda { b2.to_source(options) }.should.raise(error) 31 | end 32 | 33 | should "raise #{error} w single level nesting on same line" do 34 | b1 = lambda {|a| @x }; b2 = watever { lambda { @x } } 35 | lambda { b2.to_source(options) }.should.raise(error) 36 | end 37 | 38 | should "raise #{error} w multi level nesting on same line" do 39 | b2 = (lambda {|a| watever { lambda { @x } } }).call(1) 40 | lambda { b2.to_source(options) }.should.raise(error) 41 | end 42 | 43 | end 44 | 45 | end 46 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_multi_blocks_w_specified_attached_to_and_single_match_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_source w specified {:attached_to => ...} & single match' do 4 | 5 | options = {:attached_to => :watever} 6 | 7 | should 'handle no nesting on same line' do 8 | b1 = lambda {|a| @x1+1 }; b2 = watever { @x1+2 }; b3 = lambda { @x1+3 } 9 | b2.should.be having_source('proc { @x1+2 }', options) 10 | end 11 | 12 | should 'handle single level nesting on same line' do 13 | b1 = lambda {|a| @x2+1 }; b2 = watever { lambda { @x2+2 } } 14 | b2.should.be having_source('proc { lambda { @x2+2 } }', options) 15 | end 16 | 17 | should 'handle multi level nesting on same line' do 18 | b2 = (lambda {|a| watever { lambda { @x3 } } }).call(1) 19 | b2.should.be having_source('proc { lambda { @x3 } }', options) 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_multi_blocks_w_specified_attached_to_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_source w specified {:attached_to => ...}' do 4 | unless has_parsetree? 5 | 6 | err1 = Sourcify::MultipleMatchingProcsPerLineError 7 | err2 = Sourcify::NoMatchingProcError 8 | 9 | describe '>> w :attached_to as regexp' do 10 | 11 | should "raise Sourcify::MultipleMatchingProcsPerLineError for multiple matches" do 12 | b1 = lambda {|a| @x }; b2 = lambda { @x }; b3 = lambda { @x } 13 | lambda { b2.to_source(:attached_to => /^(?:.*?\W|)lambda(?:\W)/) }.should.raise(err1) 14 | end 15 | 16 | should "raise Sourcify::NoMatchingProcError for no match" do 17 | b1 = lambda {|a| @x }; b2 = lambda { @x }; b3 = lambda { @x } 18 | lambda { b2.to_source(:attached_to => /^(?:.*?\W|)proc(?:\W)/) }.should.raise(err2) 19 | end 20 | 21 | should "handle for single match" do 22 | b1 = lambda {|a| @x1 }; b2 = proc { @x2 }; b3 = lambda { @x3 } 23 | b2.should.be having_source('proc { @x2 }', :attached_to => /^(?:.*?\W|)proc(?:\W)/) 24 | end 25 | 26 | end 27 | 28 | describe '>> w :attached_to as string' do 29 | 30 | should "raise Sourcify::MultipleMatchingProcsPerLineError for multiple matches" do 31 | b1 = lambda {|a| @x }; b2 = lambda { @x }; b3 = lambda { @x } 32 | lambda { b2.to_source(:attached_to => 'lambda') }.should.raise(err1) 33 | end 34 | 35 | should "raise Sourcify::NoMatchingProcError for no match" do 36 | b1 = lambda {|a| @x }; b2 = lambda { @x }; b3 = lambda { @x } 37 | lambda { b2.to_source(:attached_to => 'proc') }.should.raise(err2) 38 | end 39 | 40 | should "handle for single match" do 41 | b1 = lambda {|a| @x1 }; b2 = proc { @x2 }; b3 = lambda { @x3 } 42 | b2.should.be having_source('proc { @x2 }', :attached_to => 'proc') 43 | end 44 | 45 | end 46 | 47 | describe '>> w :attached_to as symbol' do 48 | 49 | should "raise Sourcify::MultipleMatchingProcsPerLineError for multiple matches" do 50 | b1 = lambda {|a| @x }; b2 = lambda { @x }; b3 = lambda { @x } 51 | lambda { b2.to_source(:attached_to => :lambda) }.should.raise(err1) 52 | end 53 | 54 | should "raise Sourcify::NoMatchingProcError for no match" do 55 | b1 = lambda {|a| @x }; b2 = lambda { @x }; b3 = lambda { @x } 56 | lambda { b2.to_source(:attached_to => :proc) }.should.raise(err2) 57 | end 58 | 59 | should "handle for single match" do 60 | b1 = lambda {|a| @x1 }; b2 = proc { @x2 }; b3 = lambda { @x3 } 61 | b2.should.be having_source('proc { @x2 }', :attached_to => :proc) 62 | end 63 | 64 | end 65 | 66 | describe '>> w false start as a result of preceding hash' do 67 | 68 | option = {:attached_to => :watever} 69 | aa = :aa 70 | 71 | should 'handle for do ... end block' do 72 | x = watever({aa => 1, :bb => 3}) do :blah end 73 | x.should.be having_source('proc { :blah }', option) 74 | end 75 | 76 | should 'handle for { ... } block' do 77 | x = watever({aa => 1, :bb => 3}) { :blah } 78 | x.should.be having_source('proc { :blah }', option) 79 | end 80 | 81 | end 82 | 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_multi_blocks_w_specified_body_matcher_and_many_matches_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_source w specified {:attached_to => ...} & single match' do 4 | 5 | matcher = lambda {|code| code =~ /^(.*\W|)def\W/ } 6 | 7 | if has_parsetree? 8 | 9 | should 'handle no nesting on same line' do 10 | b1 = lambda {|a| @x1+1 }; b2 = lambda { @x1+2 }; b3 = lambda { @x1+3 } 11 | b2.should.be having_source('proc { @x1+2 }', &matcher) 12 | end 13 | 14 | should 'handle single level nesting on same line' do 15 | b1 = lambda {|a| @x2+1 }; b2 = lambda { lambda { @x2+2 } } 16 | b2.should.be having_source('proc { lambda { @x2+2 } }', &matcher) 17 | end 18 | 19 | should 'handle multi level nesting on same line' do 20 | b2 = (lambda {|a| lambda { lambda { @x3 } } }).call(1) 21 | b2.should.be having_source('proc { lambda { @x3 } }', &matcher) 22 | end 23 | 24 | else 25 | 26 | error = Sourcify::MultipleMatchingProcsPerLineError 27 | 28 | should "raise #{error} w no nesting on same line" do 29 | b1 = lambda {|a| @x }; b2 = lambda { def a1; end }; b3 = lambda { def a2; end } 30 | lambda { b2.to_source(&matcher) }.should.raise(error) 31 | end 32 | 33 | should "raise #{error} w single level nesting on same line" do 34 | b1 = lambda {|a| @x }; b2 = lambda { lambda { def bb; end } } 35 | lambda { b2.to_source(&matcher) }.should.raise(error) 36 | end 37 | 38 | should "raise #{error} w multi level nesting on same line" do 39 | b2 = (lambda {|a| lambda { lambda { def cc; end } } }).call(1) 40 | lambda { b2.to_source(&matcher) }.should.raise(error) 41 | end 42 | 43 | end 44 | 45 | end 46 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_multi_blocks_w_specified_body_matcher_and_no_match_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_source w specified body matcher & no match' do 4 | 5 | matcher = lambda {|code| code =~ /^(.*\W|)def\W/ } 6 | 7 | if has_parsetree? 8 | 9 | should 'handle no nesting on same line' do 10 | b1 = lambda do |a| @x1+1 end; b2 = lambda do @x1+2 end; b3 = lambda do @x1+3 end 11 | b2.should.be having_source('proc { @x1+2 }', &matcher) 12 | end 13 | 14 | should 'handle single level nesting on same line' do 15 | b1 = lambda do |a| @x2+1 end; b2 = lambda do lambda do @x2+2 end end 16 | b2.should.be having_source('proc { lambda { @x2+2 } }', &matcher) 17 | end 18 | 19 | should 'handle multi level nesting on same line' do 20 | b2 = (lambda do |a| lambda do lambda do @x3 end end end).call(1) 21 | b2.should.be having_source('proc { lambda { @x3 } }', &matcher) 22 | end 23 | 24 | else 25 | 26 | error = Sourcify::NoMatchingProcError 27 | 28 | should "raise #{error} w no nesting on same line" do 29 | b1 = lambda {|a| @x }; b2 = lambda { @x }; b3 = lambda { @x } 30 | lambda { b2.to_source(&matcher) }.should.raise(error) 31 | end 32 | 33 | should "raise #{error} w single level nesting on same line" do 34 | b1 = lambda {|a| @x }; b2 = lambda { lambda { @x } } 35 | lambda { b2.to_source(&matcher) }.should.raise(error) 36 | end 37 | 38 | should "raise #{error} w multi level nesting on same line" do 39 | b2 = (lambda {|a| lambda { lambda { @x } } }).call(1) 40 | lambda { b2.to_source(&matcher) }.should.raise(error) 41 | end 42 | 43 | end 44 | 45 | end 46 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_multi_blocks_w_specified_body_matcher_and_single_match_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_source w specified body matcher & single match' do 4 | 5 | matcher = lambda {|code| code =~ /^(.*\W|)def\W/ } 6 | 7 | should 'handle no nesting on same line' do 8 | b1 = lambda {|a| @x1+1 }; b2 = lambda { @x1+2 }; b3 = lambda { def aa; end } 9 | b3.should.be having_source('proc { def aa; end }', &matcher) 10 | end 11 | 12 | should 'handle single level nesting on same line' do 13 | b1 = lambda {|a| @x2+1 }; b2 = lambda { def bb; end; lambda { @x2+3 } } 14 | b2.should.be having_source('proc { def bb; end; lambda { @x2+3 } }', &matcher) 15 | end 16 | 17 | should 'handle multi level nesting on same line' do 18 | b2 = (lambda {|a| lambda { def cc; end; lambda { @x3+3 } } }).call(1) 19 | b2.should.be having_source('proc { def cc; end; lambda { @x3+3 } }', &matcher) 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_multi_blocks_w_specified_ignore_nested_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_source w specified {:ignore_nested => ...}' do 4 | 5 | options = {:ignore_nested => true} 6 | 7 | if has_parsetree? 8 | 9 | should 'handle no nesting on same line' do 10 | b1 = lambda {|a| @x1+1 }; b2 = lambda { @x1+2 }; b3 = lambda { @x1+3 } 11 | b2.should.be having_source('proc { @x1+2 }', options) 12 | end 13 | 14 | should 'handle single level nesting on same line' do 15 | b1 = lambda {|a| @x2+1 }; b2 = lambda { lambda { @x2+2 } } 16 | b2.should.be having_source('proc { lambda { @x2+2 } }', options) 17 | end 18 | 19 | should 'handle multi level nesting on same line (w outermost having diff arity)' do 20 | b2 = (lambda {|a| lambda { lambda { @x3 } } }).call(1) 21 | b2.should.be having_source('proc { lambda { @x3 } }', options) 22 | end 23 | 24 | else 25 | 26 | should "raise Sourcify::MultipleMatchingProcsPerLineError w no nesting on same line" do 27 | b1 = lambda {|a| @x1+1 }; b2 = lambda { @x1+2 }; b3 = lambda { @x1+3 } 28 | lambda { b2.to_source(options) }.should.raise(Sourcify::MultipleMatchingProcsPerLineError) 29 | end 30 | 31 | should "handle w single level nesting on same line" do 32 | b1 = lambda {|a| @x2+1 }; b2 = lambda { lambda { @x2+3 } } 33 | b2.should.be having_source('proc { lambda { @x2+3 } }', options) 34 | end 35 | 36 | should "raise Sourcify::NoMatchingProcError w multi level nesting on same line (w outermost having diff arity)" do 37 | b2 = (lambda {|a| lambda { lambda { @x3 } } }).call(1) 38 | lambda { b2.to_source(options) }.should.raise(Sourcify::NoMatchingProcError) 39 | end 40 | 41 | end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /spec/proc/to_source_from_multi_do_end_blocks_w_single_match_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe 'Proc#to_source from multi blocks w single match' do 4 | 5 | expected = 'proc { @x%s }' 6 | 7 | should 'skip non-matching (all do...end blocks)' do 8 | ( 9 | b1 = lambda do |a| @x1 end; b2 = lambda do @x1 end; b2 10 | ).should.be having_source(expected%1) 11 | end 12 | 13 | should 'skip non-matching (all {...} blocks)' do 14 | ( 15 | b1 = lambda {|a| @x2 }; b2 = lambda { @x2 }; b2 16 | ).should.be having_source(expected%2) 17 | end 18 | 19 | should 'skip non-matching (mixed {...} with do...end blocks)' do 20 | ( 21 | b1 = lambda {|a| @x3 }; b2 = lambda do @x3 end; b2 22 | ).should.be having_source(expected%3) 23 | end 24 | 25 | should 'skip non-matching (mixed do...end with {...} blocks)' do 26 | ( 27 | b1 = lambda do |a| @x4 end; b2 = lambda { @x4 }; b2 28 | ).should.be having_source(expected%4) 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /spec/proc/to_source_magic_file_var_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source (magic var __FILE__)" do 4 | 5 | should 'handle single standalone' do 6 | lambda { __FILE__ }.should.be having_source(%(proc { "#{__FILE__}" })) 7 | end 8 | 9 | should 'handle multiple standalones' do 10 | lambda { 11 | [ 12 | __FILE__, __FILE__, 13 | __FILE__ 14 | ] 15 | }.should.be having_source(%Q( 16 | proc do 17 | [ 18 | "#{__FILE__}", "#{__FILE__}", 19 | "#{__FILE__}" 20 | ] 21 | end 22 | )) 23 | end 24 | 25 | should 'handle single interpolation' do 26 | lambda { "#{__FILE__}" }.should.be having_source(%(proc { "#{__FILE__}" })) 27 | end 28 | 29 | should 'handle multiple interpolation (separate)' do 30 | lambda { 31 | [ 32 | "#{__FILE__}", "#{__FILE__}", 33 | "#{__FILE__}" 34 | ] 35 | }.should.be having_source(%Q( 36 | proc do 37 | [ 38 | "#{__FILE__}", "#{__FILE__}", 39 | "#{__FILE__}" 40 | ] 41 | end 42 | )) 43 | end 44 | 45 | should 'handle multiple interpolation (together)' do 46 | lambda { 47 | < ...}' do 4 | 5 | describe '>> w true' do 6 | 7 | options = {:strip_enclosure => true} 8 | 9 | should 'strip enclosing proc wo arg' do 10 | lambda { a+b }.should.be having_source('a+b', options) 11 | end 12 | 13 | should 'strip enclosing proc w arg' do 14 | lambda {|a| a+b }.should.be having_source('a+b', options) 15 | end 16 | 17 | end 18 | 19 | describe '>> w false' do 20 | 21 | options = {:strip_enclosure => false} 22 | 23 | should 'not strip enclosing proc wo arg' do 24 | lambda { a+b }.should.be having_source('proc { a+b }', options) 25 | end 26 | 27 | should 'not strip enclosing proc w arg' do 28 | lambda {|a| a+b }.should.be having_source('proc {|a| a+b }', options) 29 | end 30 | 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /spec/proc/to_source_within_irb_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source within IRB" do 4 | 5 | class << self 6 | 7 | def irb_eval(string) 8 | irb_exec(string)[-1] 9 | end 10 | 11 | def equal_to(expected) 12 | lambda {|found| normalize_code(found) == normalize_code(expected) } 13 | end 14 | 15 | end 16 | 17 | should 'handle basic' do 18 | irb_eval(%Q( 19 | x = lambda { 1+2 } 20 | y = lambda { 2+3 } 21 | z = lambda { 3+4 } 22 | y.to_source 23 | )).should.be equal_to('proc { 2+3 }') 24 | end 25 | 26 | should 'handle magic variable __FILE__' do 27 | irb_eval(%Q( 28 | lambda { __FILE__ }.to_source 29 | )).should.be equal_to('proc { "(irb)" }') 30 | end 31 | 32 | should 'handle magic variable __LINE__' do 33 | irb_eval(%Q( 34 | lambda { __LINE__ }.to_source 35 | )).should.be equal_to('proc { 2 }') 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /spec/proc/to_source_within_pry_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper') 2 | 3 | describe "Proc#to_source within PRY" do 4 | 5 | class << self 6 | 7 | def pry_eval(string) 8 | pry_exec(string)[-1] 9 | end 10 | 11 | def equal_to(expected) 12 | lambda {|found| normalize_code(found) == normalize_code(expected) } 13 | end 14 | 15 | end 16 | 17 | should 'handle basic' do 18 | pry_eval(%Q( 19 | x = lambda { 1+2 } 20 | y = lambda { 2+3 } 21 | z = lambda { 3+4 } 22 | y.to_source 23 | )).should.be equal_to('proc { 2+3 }') 24 | end 25 | 26 | should 'handle magic variable __FILE__' do 27 | pry_eval(%Q( 28 | # NOTE: this line is needed to fix one-liner issue w pry 29 | lambda { __FILE__ }.to_source 30 | )).should.be equal_to('proc { "(pry)" }') 31 | end 32 | 33 | should 'handle magic variable __LINE__' do 34 | pry_eval(%Q( 35 | # NOTE: this line is needed to fix one-liner issue w pry 36 | lambda { __LINE__ }.to_source 37 | )).should.be equal_to('proc { 2 }') 38 | end 39 | 40 | 41 | # NOTE: The rest address issue#22, kudos goes to @scooter-dangle 42 | # for providing such detailed examples :) 43 | should 'handle a single upward scroll' do 44 | pry_eval(%Q( 45 | a = lambda { |proc| proc.to_source } 46 | a[(lambda { 0 })] 47 | a[(lambda { 1 })] 48 |  49 | )).should.be equal_to('proc { 1 }') 50 | end 51 | 52 | should 'handle a double upward scroll' do 53 | pry_eval(%Q( 54 | a = lambda { |proc| proc.to_source } 55 | a[(lambda { 0 })] 56 | a[(lambda { 1 })] 57 |  58 | )).should.be equal_to('proc { 0 }') 59 | end 60 | 61 | end 62 | -------------------------------------------------------------------------------- /spec/raw_scanner/block_comment_shared_spec.rb: -------------------------------------------------------------------------------- 1 | shared "Block comment (=begin ... =end)" do 2 | 3 | should 'handle =begin\n ... =end\n' do 4 | process(<}] 6 | ).each do |q1,q2| 7 | ['Q', 'W', 'x', 'r', ''].each do |t| 8 | 9 | should "handle %#{t}#{q1}...#{q2} (wo nesting (single))" do 10 | process(" xx; %#{t}#{q1}h\#{%#{t}#{q1}ell#{q2}}o#{q2} "). 11 | should.include([:dstring, "%#{t}#{q1}h\#{%#{t}#{q1}ell#{q2}}o#{q2}"]) 12 | end 13 | 14 | should "handle %#{t}#{q1}...#{q2} (wo nesting (multiple))" do 15 | tokens = process(" xx; %#{t}#{q1}h\#{%#{t}#{q1}ell#{q2}}o#{q2} %#{t}#{q1}w\#{%#{t}#{q1}orl#{q2}}d#{q2} ") 16 | tokens.should.include([:dstring, "%#{t}#{q1}h\#{%#{t}#{q1}ell#{q2}}o#{q2}"]) 17 | tokens.should.include([:dstring, "%#{t}#{q1}w\#{%#{t}#{q1}orl#{q2}}d#{q2}"]) 18 | end 19 | 20 | should "handle %#{t}#{q1}...#{q2} (w nesting (single))" do 21 | process(" xx; %#{t}#{q1}h\#{%#{t}#{q1}e\#{%#{t}#{q1}l#{q2}}l#{q2}}o#{q2} "). 22 | should.include([:dstring, "%#{t}#{q1}h\#{%#{t}#{q1}e\#{%#{t}#{q1}l#{q2}}l#{q2}}o#{q2}"]) 23 | end 24 | 25 | should "handle %#{t}#{q1}...#{q2} (w nesting (multiple))" do 26 | tokens = process(" xx; " + 27 | "%#{t}#{q1}h\#{%#{t}#{q1}e\#{%#{t}#{q1}l#{q2}}l#{q2}}o#{q2} " + 28 | "%#{t}#{q1}w\#{%#{t}#{q1}o\#{%#{t}#{q1}r#{q2}}l#{q2}}d#{q2} " 29 | ) 30 | tokens.should.include([:dstring, "%#{t}#{q1}h\#{%#{t}#{q1}e\#{%#{t}#{q1}l#{q2}}l#{q2}}o#{q2}"]) 31 | tokens.should.include([:dstring, "%#{t}#{q1}w\#{%#{t}#{q1}o\#{%#{t}#{q1}r#{q2}}l#{q2}}d#{q2}"]) 32 | end 33 | 34 | end 35 | end 36 | 37 | %w{" / `}.each do |q| 38 | 39 | should "handle #{q}...#{q} (wo escape (single))" do 40 | process(%Q( xx; #{q}hello#{q} )).should.include([:dstring, %Q(#{q}hello#{q})]) 41 | end 42 | 43 | should "handle #{q}...#{q} (wo escape & multiple)" do 44 | tokens = process(%Q( xx; #{q}hello#{q} ; #{q}world#{q} )) 45 | tokens.should.include([:dstring, %Q(#{q}hello#{q})]) 46 | tokens.should.include([:dstring, %Q(#{q}world#{q})]) 47 | end 48 | 49 | should "handle #{q}...#{q} (w escape (single))" do 50 | process(%Q( xx; #{q}hel\\#{q}lo#{q} )).should. 51 | include([:dstring, %Q(#{q}hel\\#{q}lo#{q})]) 52 | end 53 | 54 | should "handle #{q}...#{q} (w escape (multiple))" do 55 | process(%Q( xx; #{q}h\\#{q}el\\#{q}lo#{q} )).should.include([:dstring, %Q(#{q}h\\#{q}el\\#{q}lo#{q})]) 56 | end 57 | 58 | end 59 | 60 | end 61 | -------------------------------------------------------------------------------- /spec/raw_scanner/double_quote_str_wo_interpolation_shared_spec.rb: -------------------------------------------------------------------------------- 1 | shared 'Double quote strings (wo interpolation)' do 2 | 3 | %w{~ ` ! @ # $ % ^ & * _ - + = | \\ ; : ' " , . ? /}.map{|w| [w,w] }.concat( 4 | [%w{( )}, %w{[ ]}, %w({ }), %w{< >}] 5 | ).each do |q1,q2| 6 | ['Q', 'W', 'x', 'r', ''].each do |t| 7 | 8 | should "handle %#{t}#{q1}...#{q2} (wo escape (single))" do 9 | process(" xx; %#{t}#{q1}hello#{q2} ").should.include([:dstring, "%#{t}#{q1}hello#{q2}"]) 10 | end 11 | 12 | should "handle %#{t}#{q1}...#{q2} (wo escape (multiple))" do 13 | tokens = process(" xx; %#{t}#{q1}hello#{q2} %#{t}#{q1}world#{q2} ") 14 | tokens.should.include([:dstring, "%#{t}#{q1}hello#{q2}"]) 15 | tokens.should.include([:dstring, "%#{t}#{q1}world#{q2}"]) 16 | end 17 | 18 | # NOTE: We are skipping '\\' cos %Q\hel\\o\ is always raise SyntaxError no matter 19 | # how many backslashes we add 20 | unless q1 == '\\' 21 | 22 | should "handle %#{t}#{q1}...#{q2} (w escape (single))" do 23 | process(" xx; %#{t}#{q1}hel\\#{q2}lo#{q2} ").should. 24 | include([:dstring, "%#{t}#{q1}hel\\#{q2}lo#{q2}"]) 25 | end 26 | 27 | should "handle %#{t}#{q1}...#{q2} (w escape (multiple))" do 28 | process(" xx; %#{t}#{q1}h\\#{q2}el\\#{q2}lo#{q2} ").should. 29 | include([:dstring, "%#{t}#{q1}h\\#{q2}el\\#{q2}lo#{q2}"]) 30 | end 31 | 32 | should "handle %#{t}#{q1}\\\\#{q2}" do 33 | process(" xx; %#{t}#{q1}\\\\#{q2} %#{t}#{q2}lo#{q2} ").should. 34 | include([:dstring, "%#{t}#{q1}\\\\#{q2}"]) 35 | end 36 | 37 | should "handle %#{t}#{q1}#{q2}" do 38 | process(" xx; %#{t}#{q1}#{q2} %#{t}#{q2}lo#{q2} ").should. 39 | include([:dstring, "%#{t}#{q1}#{q2}"]) 40 | end 41 | 42 | end 43 | 44 | end 45 | end 46 | 47 | %w{" / `}.each do |q| 48 | 49 | should "handle #{q}...#{q} (wo escape (single))" do 50 | process(%Q( xx; #{q}hello#{q} )).should.include([:dstring, %Q(#{q}hello#{q})]) 51 | end 52 | 53 | should "handle #{q}...#{q} (wo escape & multiple)" do 54 | tokens = process(%Q( xx; #{q}hello#{q} ; #{q}world#{q} )) 55 | tokens.should.include([:dstring, %Q(#{q}hello#{q})]) 56 | tokens.should.include([:dstring, %Q(#{q}world#{q})]) 57 | end 58 | 59 | should "handle #{q}...#{q} (w escape (single))" do 60 | process(%Q( xx; #{q}hel\\#{q}lo#{q} )).should.include([:dstring, %Q(#{q}hel\\#{q}lo#{q})]) 61 | end 62 | 63 | should "handle #{q}...#{q} (w escape (multiple))" do 64 | process(%Q( xx; #{q}h\\#{q}el\\#{q}lo#{q} )).should. 65 | include([:dstring, %Q(#{q}h\\#{q}el\\#{q}lo#{q})]) 66 | end 67 | 68 | should "handle #{q}\\\\#{q}" do 69 | process(%Q( 70 | aa; #{q}\\\\#{q} 71 | cc 72 | #{q}dd#{q} 73 | )).should.include([:dstring, "#{q}\\\\#{q}"]) 74 | end 75 | 76 | should "handle #{q}#{q}" do 77 | process(%Q( 78 | aa; #{q}#{q} 79 | cc 80 | #{q}dd#{q} 81 | )).should.include([:dstring, "#{q}#{q}"]) 82 | end 83 | 84 | end 85 | 86 | end 87 | -------------------------------------------------------------------------------- /spec/raw_scanner/heredoc_w_indent_shared_spec.rb: -------------------------------------------------------------------------------- 1 | shared "Heredoc (w indent)" do 2 | %w{X "X" 'X'}.each do |tag| 3 | 4 | should "handle <<-#{tag}\\n .. \\nX\\n" do 5 | process(%Q( 6 | s <<-#{tag} 7 | aa 8 | X 9 | )).should.include([:heredoc, "<<-#{tag}\n aa \nX"]) 10 | end 11 | 12 | should "handle <<-#{tag}\\n .. \\n X\\n" do 13 | process(%Q( 14 | s <<-#{tag} 15 | aa 16 | X 17 | )).should.include([:heredoc, "<<-#{tag}\n aa \n X"]) 18 | end 19 | 20 | should "not handle <<-#{tag} \\n .. \\nX\\n" do 21 | process(%Q( 22 | s <<-#{tag} 23 | aa 24 | X 25 | )).should.not.include([:heredoc, "<<-#{tag} \n aa \n X"]) 26 | end 27 | 28 | should "not handle <<-#{tag}\\n .. \\nX \\n" do 29 | process(%Q( 30 | s <<-#{tag} 31 | aa 32 | X 33 | )).should.not.include([:heredoc, "<<-#{tag}\n aa \nX "]) 34 | end 35 | 36 | should "not handle class <<-#{tag}\\n .. \\nX \\n" do 37 | process(%Q( 38 | class <<-#{tag} 39 | aa 40 | X 41 | )).should.not.include([:heredoc, "<<-#{tag}\n aa \nX"]) 42 | end 43 | 44 | should "handle xclass <<-#{tag}\\n .. \\nX \\n" do 45 | process(%Q( 46 | xclass <<-#{tag} 47 | aa 48 | X 49 | )).should.include([:heredoc, "<<-#{tag}\n aa \nX"]) 50 | end 51 | 52 | should "handle classx <<-#{tag}\\n .. \\nX \\n" do 53 | process(%Q( 54 | classx <<-#{tag} 55 | aa 56 | X 57 | )).should.include([:heredoc, "<<-#{tag}\n aa \nX"]) 58 | end 59 | 60 | should "handle <<-#{tag}\\n .. \\nX \\n" do 61 | process(%Q( 62 | <<-#{tag} 63 | aa 64 | X 65 | )).should.include([:heredoc, "<<-#{tag}\n aa \nX"]) 66 | end 67 | 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /spec/raw_scanner/heredoc_wo_indent_shared_spec.rb: -------------------------------------------------------------------------------- 1 | shared "Heredoc (wo indent)" do 2 | %w{X "X" 'X'}.each do |tag| 3 | 4 | should "handle <<#{tag}\\n .. \\nX\\n" do 5 | process(%Q( 6 | s <<#{tag} 7 | aa 8 | X 9 | )).should.include([:heredoc, "<<#{tag}\n aa \nX"]) 10 | end 11 | 12 | should "not handle <<#{tag} \\n .. \\nX\\n" do 13 | process(%Q( 14 | s << #{tag} 15 | aa 16 | X 17 | )).should.not.include([:heredoc, "<<#{tag} \n aa \nX"]) 18 | end 19 | 20 | should "not handle <<#{tag}\\n .. \\n X\\n" do 21 | process(%Q( 22 | s <<#{tag} 23 | aa 24 | X 25 | )).should.not.include([:heredoc, "<<#{tag} \n aa \n X"]) 26 | end 27 | 28 | should "not handle <<#{tag}\\n .. \\nX \\n" do 29 | process(%Q( 30 | s <<#{tag} 31 | aa 32 | X 33 | )).should.not.include([:heredoc, "<<#{tag} \n aa \nX "]) 34 | end 35 | 36 | should "not handle class <<#{tag}\\n .. \\nX \\n" do 37 | process(%Q( 38 | 39 | class <<#{tag} 40 | aa 41 | X 42 | )).should.not.include([:heredoc, "<<#{tag}\n aa \nX"]) 43 | end 44 | 45 | should "handle xclass <<#{tag}\\n .. \\nX \\n" do 46 | process(%Q( 47 | xclass <<#{tag} 48 | aa 49 | X 50 | )).should.include([:heredoc, "<<#{tag}\n aa \nX"]) 51 | end 52 | 53 | should "handle classx <<#{tag}\\n .. \\nX \\n" do 54 | process(%Q( 55 | classx <<#{tag} 56 | aa 57 | X 58 | )).should.include([:heredoc, "<<#{tag}\n aa \nX"]) 59 | end 60 | 61 | should "handle <<#{tag}\\n .. \\nX \\n" do 62 | process(%Q( 63 | <<#{tag} 64 | aa 65 | X 66 | )).should.include([:heredoc, "<<#{tag}\n aa \nX"]) 67 | end 68 | 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /spec/raw_scanner/kw_block_start_alias1_shared_spec.rb: -------------------------------------------------------------------------------- 1 | shared "Keyword block start alias #1 (incrementing counter by 1)" do 2 | kw_block_start_alias1.each do |kw| 3 | 4 | %w{_ x 1}.each do |c| 5 | should "not increment counter with ... (#{kw}#{c} ...)" do 6 | kw_block_start_counter(<}] 5 | ).each do |q1,q2| 6 | %w{q w}.each do |t| 7 | 8 | should "handle %#{t}#{q1}...#{q2} (wo escape (single))" do 9 | process(" xx %#{t}#{q1}hello#{q2} ").should.include([:sstring, "%#{t}#{q1}hello#{q2}"]) 10 | end 11 | 12 | should "handle %#{t}#{q1}...#{q2} (wo escape (multiple))" do 13 | tokens = process(" xx %#{t}#{q1}hello#{q2} %#{t}#{q1}world#{q2} ") 14 | tokens.should.include([:sstring, "%#{t}#{q1}hello#{q2}"]) 15 | tokens.should.include([:sstring, "%#{t}#{q1}world#{q2}"]) 16 | end 17 | 18 | should "handle %#{t}#{q1}...#{q2} (w escape (single))" do 19 | process(" xx %#{t}#{q1}hel\\#{q2}lo#{q2} ").should. 20 | include([:sstring, "%#{t}#{q1}hel\\#{q2}lo#{q2}"]) 21 | end 22 | 23 | should "handle %#{t}#{q1}...#{q2} (w escape (multiple))" do 24 | process(" xx %#{t}#{q1}h\\#{q2}el\\#{q2}lo#{q2} ").should. 25 | include([:sstring, "%#{t}#{q1}h\\#{q2}el\\#{q2}lo#{q2}"]) 26 | end 27 | 28 | # NOTE: We are skipping '\\' cos %q\\\\ is always raise SyntaxError no matter 29 | # how many backslashes we add 30 | unless q1 == '\\' 31 | should "handle %#{t}#{q1}\\\\#{q2}" do 32 | process(" xx %#{t}#{q1}\\\\#{q2} %#{t}#{q2}lo#{q2} ").should. 33 | include([:sstring, "%#{t}#{q1}\\\\#{q2}"]) 34 | end 35 | end 36 | 37 | should "handle %#{t}#{q1}#{q2}" do 38 | process(" xx %#{t}#{q1}#{q2} %#{t}#{q2}lo#{q2} ").should. 39 | include([:sstring, "%#{t}#{q1}#{q2}"]) 40 | end 41 | 42 | end 43 | end 44 | 45 | should "handle '...' (wo escape (single))" do 46 | process(" xx 'hello' ").should.include([:sstring, "'hello'"]) 47 | end 48 | 49 | should "handle '...' (wo escape (multiple))" do 50 | tokens = process(" xx 'hello' 'world' ") 51 | tokens.should.include([:sstring, "'hello'"]) 52 | tokens.should.include([:sstring, "'world'"]) 53 | end 54 | 55 | should "handle '...' (w escape (single))" do 56 | process(" xx 'hel\\'lo' ").should.include([:sstring, "'hel\\'lo'"]) 57 | end 58 | 59 | should "handle '...' (w escape (multiple))" do 60 | process(" xx 'h\\'el\\'lo' ").should.include([:sstring, "'h\\'el\\'lo'"]) 61 | end 62 | 63 | should "handle '\\\\'" do 64 | process(%q( 65 | aa '\\\\' 66 | cc 67 | 'dd' 68 | )).should.include([:sstring, "'\\\\'"]) 69 | end 70 | 71 | should "handle ''" do 72 | process(%q( 73 | aa '' 74 | cc 75 | 'dd' 76 | )).should.include([:sstring, "''"]) 77 | end 78 | 79 | end 80 | -------------------------------------------------------------------------------- /spec/raw_scanner/slash_operator_shared_spec.rb: -------------------------------------------------------------------------------- 1 | shared "Slash operator" do 2 | 3 | should 'handle w preceding variable' do 4 | process(%Q(a / b)).should.include([:op, '/']) 5 | end 6 | 7 | should 'handle w preceding constant' do 8 | process(%Q(A / b)).should.include([:op, '/']) 9 | end 10 | 11 | should 'handle w preceding symbol' do 12 | process(%Q(:a / b)).should.include([:op, '/']) 13 | end 14 | 15 | should 'handle w preceding digit' do 16 | process(%Q(0 / b)).should.include([:op, '/']) 17 | end 18 | 19 | should 'handle w preceding a~f' do 20 | process(%Q(0xa / b)).should.include([:op, '/']) 21 | process(%Q(0xb / b)).should.include([:op, '/']) 22 | process(%Q(0xc / b)).should.include([:op, '/']) 23 | process(%Q(0xd / b)).should.include([:op, '/']) 24 | process(%Q(0xe / b)).should.include([:op, '/']) 25 | process(%Q(0xf / b)).should.include([:op, '/']) 26 | end 27 | 28 | should 'handle w preceding dstring' do 29 | process(%Q("a" / b)).should.include([:op, '/']) 30 | end 31 | 32 | should 'handle w preceding sstring' do 33 | process(%Q('a' / b)).should.include([:op, '/']) 34 | end 35 | 36 | should "handle w preceding ')' char" do 37 | process(%Q{) / b}).should.include([:op, '/']) 38 | 39 | end 40 | 41 | should "handle w preceding ']' char" do 42 | process(%Q(] / b)).should.include([:op, '/']) 43 | end 44 | 45 | should "handle w preceding '}' char" do 46 | process(%Q(} / b)).should.include([:op, '/']) 47 | end 48 | 49 | should "not handle w preceding newline" do 50 | process(%Q( 51 | / b / 52 | )).should.not.include([:op, '/']) 53 | end 54 | 55 | should "not handle w preceding ';' char" do 56 | process(%Q(; / b /)).should.not.include([:op, '/']) 57 | end 58 | 59 | should "not handle w preceding '(' char" do 60 | process(%Q{( / b /}).should.not.include([:op, '/']) 61 | end 62 | 63 | should "not handle w preceding '{' char" do 64 | process(%Q({ / b /)).should.not.include([:op, '/']) 65 | end 66 | 67 | should "not handle w preceding '[' char" do 68 | process(%Q([ / b /)).should.not.include([:op, '/']) 69 | end 70 | 71 | end 72 | -------------------------------------------------------------------------------- /spec/run_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -z "$TRAVIS" ]; then 3 | echo '' 4 | echo `gem env | grep 'INSTALLATION DIRECTORY' | sed 's/.*\/\(.*\)/\1:/'` 5 | rm -rf ~/.ruby_inline/*ParseTree* 6 | fi 7 | 8 | SUPPORTS_METHOD_TO_SOURCE=`ruby -e ' 9 | begin 10 | [:source_location, :parameters].each{|meth| 1.method(:to_s).send(meth) } 11 | raise RuntimeError if RUBY_PLATFORM =~ /java/i 12 | puts :true 13 | rescue NoMethodError, RuntimeError 14 | puts :false 15 | end 16 | '` 17 | 18 | if [ "$SUPPORTS_METHOD_TO_SOURCE" == "true" ]; then 19 | bundle exec bacon spec/{proc,method}/*/*_spec.rb spec/{proc,method}/*_spec.rb 20 | else 21 | echo "NOTE: This ruby doesn't support Method#to_source (& friends) !!" 22 | bundle exec bacon spec/proc/*/*_spec.rb spec/{proc,no_method}/*_spec.rb 23 | fi 24 | 25 | # __END__ 26 | --------------------------------------------------------------------------------