ruby-next 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -1
  3. data/README.md +11 -7
  4. metadata +3 -48
  5. data/bin/parse +0 -19
  6. data/bin/ruby-next +0 -16
  7. data/bin/transform +0 -21
  8. data/lib/ruby-next.rb +0 -37
  9. data/lib/ruby-next/cli.rb +0 -94
  10. data/lib/ruby-next/commands/base.rb +0 -42
  11. data/lib/ruby-next/commands/core_ext.rb +0 -166
  12. data/lib/ruby-next/commands/nextify.rb +0 -133
  13. data/lib/ruby-next/core.rb +0 -182
  14. data/lib/ruby-next/core/array/deconstruct.rb +0 -21
  15. data/lib/ruby-next/core/array/difference_union_intersection.rb +0 -25
  16. data/lib/ruby-next/core/constants/no_matching_pattern_error.rb +0 -17
  17. data/lib/ruby-next/core/enumerable/filter.rb +0 -25
  18. data/lib/ruby-next/core/enumerable/filter_map.rb +0 -38
  19. data/lib/ruby-next/core/enumerable/tally.rb +0 -14
  20. data/lib/ruby-next/core/enumerator/produce.rb +0 -20
  21. data/lib/ruby-next/core/hash/deconstruct_keys.rb +0 -21
  22. data/lib/ruby-next/core/hash/merge.rb +0 -14
  23. data/lib/ruby-next/core/kernel/then.rb +0 -10
  24. data/lib/ruby-next/core/proc/compose.rb +0 -19
  25. data/lib/ruby-next/core/runtime.rb +0 -10
  26. data/lib/ruby-next/core/string/split.rb +0 -11
  27. data/lib/ruby-next/core/struct/deconstruct.rb +0 -7
  28. data/lib/ruby-next/core/struct/deconstruct_keys.rb +0 -34
  29. data/lib/ruby-next/core/time/ceil.rb +0 -10
  30. data/lib/ruby-next/core/time/floor.rb +0 -9
  31. data/lib/ruby-next/core/unboundmethod/bind_call.rb +0 -9
  32. data/lib/ruby-next/core_ext.rb +0 -18
  33. data/lib/ruby-next/language.rb +0 -119
  34. data/lib/ruby-next/language/bootsnap.rb +0 -26
  35. data/lib/ruby-next/language/eval.rb +0 -64
  36. data/lib/ruby-next/language/parser.rb +0 -28
  37. data/lib/ruby-next/language/rewriters/args_forward.rb +0 -57
  38. data/lib/ruby-next/language/rewriters/base.rb +0 -105
  39. data/lib/ruby-next/language/rewriters/endless_range.rb +0 -60
  40. data/lib/ruby-next/language/rewriters/method_reference.rb +0 -33
  41. data/lib/ruby-next/language/rewriters/numbered_params.rb +0 -41
  42. data/lib/ruby-next/language/rewriters/pattern_matching.rb +0 -541
  43. data/lib/ruby-next/language/runtime.rb +0 -95
  44. data/lib/ruby-next/language/setup.rb +0 -43
  45. data/lib/ruby-next/language/unparser.rb +0 -8
  46. data/lib/ruby-next/utils.rb +0 -36
  47. data/lib/ruby-next/version.rb +0 -5
  48. data/lib/uby-next.rb +0 -68
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0378d5cef399b739144ff46957ae5156da88669d9fcda922ccc3b33e1996b1a1'
4
- data.tar.gz: 7ffb9dcd0eb9a9ec03ec253ad49d10f71cd83706820e7ddc79f6a8049f5fca4e
3
+ metadata.gz: 6cc67691b20d3fa1a528a3f42d306f634b4b23aa8d5d876c4441e5cfdc08bbd9
4
+ data.tar.gz: ba3efeed90aefc8ab2f50979792445e5dae7dc3447715bdc38155889459b8807
5
5
  SHA512:
6
- metadata.gz: 7eec4a20c21f2657381e79d1dde96d46b135e35401764e620de7fca31d7b7584ec610e97ed7485bee4ec300ae10ef0bfb458ed151978a9f1b42c5c1da95ec17b
7
- data.tar.gz: b193984197fd6cf23836f3945c4586d7deba51c096ffa6beef6933ba458c46c2232ad3326b35a546e31515de49789ad9b553439820ef0f3a72d6f287917ebd07
6
+ metadata.gz: 7fd55f852c960fe4230abb6ebd512bd0b22b084659486484bfc45b3b7ee987ff77fcc9ab5932e880175063ea492bb746dc88d2e0a230fd77b9dfee78b275d88f
7
+ data.tar.gz: 25c136bb7761113535006f1de10fe34fafd69520c633b7693b59afca63eb7b6b64593529f80c61b494325c3a6bd0864bfd30a011502dcbd4ff41fb54911d0f4e
data/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.4.0 (2020-03-09)
6
+
7
+ - Optimize pattern matching transpiled code. ([@palkan][])
8
+
9
+ For array patterns, transpiled code is ~1.5-2x faster than native.
10
+ For hash patterns it's about the same.
11
+
12
+ - Pattern matching is 100% compatible with RubySpec. ([@palkan][])
13
+
14
+ - Add `Symbol#start_with?/end_with?`. ([@palkan][])
15
+
5
16
  ## 0.3.0 (2020-02-14) 💕
6
17
 
7
18
  - Add `Time#floor` and `Time#ceil`. ([@palkan][])
@@ -48,7 +59,7 @@ You can still use this feature by enabling it explicitly (see Readme).
48
59
  - Support in modifier. ([@palkan][])
49
60
 
50
61
  ```ruby
51
- {a:1, b: 2} in {a:, **}
62
+ {a: 1, b: 2} in {a:, **}
52
63
  p a #=> 1
53
64
  ```
54
65
 
data/README.md CHANGED
@@ -3,9 +3,10 @@
3
3
 
4
4
  # Ruby Next
5
5
 
6
- > Make all Rubies quack like edge Ruby!
6
+ <img align="right" height="184"
7
+ title="Ruby Next logo" src="./assets/images/logo.svg">
7
8
 
8
- Ruby Next is a collection of **polyfills** and a **transpiler** for supporting the latest and upcoming Ruby features (APIs and syntax) in older versions and alternative implementations. For example, you can use pattern matching and `Kernel#then` in Ruby 2.5 or [mruby][].
9
+ Ruby Next is a **transpiler** and a collection of **polyfills** for supporting the latest and upcoming Ruby features (APIs and syntax) in older versions and alternative implementations. For example, you can use pattern matching and `Kernel#then` in Ruby 2.5 or [mruby][].
9
10
 
10
11
  Who might be interested in Ruby Next?
11
12
 
@@ -14,9 +15,10 @@ Who might be interested in Ruby Next?
14
15
  - **Users of non-MRI implementations** such as [mruby][], [JRuby][], [TruffleRuby][], [Opal][], [RubyMotion][], [Artichoke][], [Prism][].
15
16
 
16
17
  Ruby Next also aims to help the community to assess new, _experimental_, MRI features by making it easier to play with them.
17
- That's why Ruby Next implements the `trunk` features as fast as possible.
18
+ That's why Ruby Next implements the `master` features as fast as possible.
18
19
 
19
- _⚡️ The project is in a **beta** phase. That means that the main functionality has been implemented (see [the list][features]) and APIs shouldn't change a lot in the nearest future. On the other hand, the number of users/projects is not enough to say we're "production-ready". So, can't wait to hear your feedback 🙂_
20
+ <a href="https://evilmartians.com/?utm_source=ruby-next">
21
+ <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
20
22
 
21
23
  ## Links
22
24
 
@@ -92,7 +94,9 @@ gem "ruby-next"
92
94
 
93
95
  # gemspec
94
96
  spec.add_dependency "ruby-next"
97
+ ```
95
98
 
99
+ ```sh
96
100
  # or install globally
97
101
  gem install ruby-next
98
102
  ```
@@ -164,7 +168,7 @@ The behaviour depends on whether you transpile a single file or a directory:
164
168
 
165
169
  ```sh
166
170
  $ ruby-next nextify my_ruby.rb -o my_ruby_next.rb -V
167
- RubyNext core strategy: refine
171
+ Ruby Next core strategy: refine
168
172
  Generated: my_ruby_next.rb
169
173
  ```
170
174
 
@@ -298,7 +302,7 @@ Then, add to your Gemfile:
298
302
 
299
303
  ```ruby
300
304
  source "https://rubygems.pkg.github.com/ruby-next" do
301
- gem "parser", "2.7.0.100"
305
+ gem "parser", "~> 2.7.0.100", "< 2.7.1"
302
306
  end
303
307
 
304
308
  gem "ruby-next"
@@ -311,7 +315,7 @@ gem "ruby-next"
311
315
  You can install `ruby-next` globally by running the following commands:
312
316
 
313
317
  ```sh
314
- gem install parser -v "2.7.0.100" --source "https://USERNAME:ACCESS_TOKEN@rubygems.pkg.github.com/ruby-next"
318
+ gem install parser -v "~> 2.7.0.100" -v "< 2.7.1" --source "https://USERNAME:ACCESS_TOKEN@rubygems.pkg.github.com/ruby-next"
315
319
  gem install ruby-next
316
320
  ```
317
321
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-next
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-15 00:00:00.000000000 Z
11
+ date: 2020-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-next-core
@@ -57,58 +57,13 @@ description: "\n Ruby Next is a collection of polyfills and a transpiler for
57
57
  (such as mruby, JRuby, Opal, Artichoke, RubyMotion, etc.).\n "
58
58
  email:
59
59
  - dementiev.vm@gmail.com
60
- executables:
61
- - ruby-next
60
+ executables: []
62
61
  extensions: []
63
62
  extra_rdoc_files: []
64
63
  files:
65
64
  - CHANGELOG.md
66
65
  - LICENSE.txt
67
66
  - README.md
68
- - bin/parse
69
- - bin/ruby-next
70
- - bin/transform
71
- - lib/ruby-next.rb
72
- - lib/ruby-next/cli.rb
73
- - lib/ruby-next/commands/base.rb
74
- - lib/ruby-next/commands/core_ext.rb
75
- - lib/ruby-next/commands/nextify.rb
76
- - lib/ruby-next/core.rb
77
- - lib/ruby-next/core/array/deconstruct.rb
78
- - lib/ruby-next/core/array/difference_union_intersection.rb
79
- - lib/ruby-next/core/constants/no_matching_pattern_error.rb
80
- - lib/ruby-next/core/enumerable/filter.rb
81
- - lib/ruby-next/core/enumerable/filter_map.rb
82
- - lib/ruby-next/core/enumerable/tally.rb
83
- - lib/ruby-next/core/enumerator/produce.rb
84
- - lib/ruby-next/core/hash/deconstruct_keys.rb
85
- - lib/ruby-next/core/hash/merge.rb
86
- - lib/ruby-next/core/kernel/then.rb
87
- - lib/ruby-next/core/proc/compose.rb
88
- - lib/ruby-next/core/runtime.rb
89
- - lib/ruby-next/core/string/split.rb
90
- - lib/ruby-next/core/struct/deconstruct.rb
91
- - lib/ruby-next/core/struct/deconstruct_keys.rb
92
- - lib/ruby-next/core/time/ceil.rb
93
- - lib/ruby-next/core/time/floor.rb
94
- - lib/ruby-next/core/unboundmethod/bind_call.rb
95
- - lib/ruby-next/core_ext.rb
96
- - lib/ruby-next/language.rb
97
- - lib/ruby-next/language/bootsnap.rb
98
- - lib/ruby-next/language/eval.rb
99
- - lib/ruby-next/language/parser.rb
100
- - lib/ruby-next/language/rewriters/args_forward.rb
101
- - lib/ruby-next/language/rewriters/base.rb
102
- - lib/ruby-next/language/rewriters/endless_range.rb
103
- - lib/ruby-next/language/rewriters/method_reference.rb
104
- - lib/ruby-next/language/rewriters/numbered_params.rb
105
- - lib/ruby-next/language/rewriters/pattern_matching.rb
106
- - lib/ruby-next/language/runtime.rb
107
- - lib/ruby-next/language/setup.rb
108
- - lib/ruby-next/language/unparser.rb
109
- - lib/ruby-next/utils.rb
110
- - lib/ruby-next/version.rb
111
- - lib/uby-next.rb
112
67
  homepage: http://github.com/palkan/ruby-next
113
68
  licenses:
114
69
  - MIT
data/bin/parse DELETED
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- lib = File.expand_path("../../lib", __FILE__)
4
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- $VERBOSE = nil
6
-
7
- require "bundler/setup"
8
-
9
- require "ruby-next/language"
10
-
11
- contents =
12
- if File.exist?(ARGV[0])
13
- File.read(ARGV[0])
14
- else
15
- ARGV[0]
16
- end
17
-
18
- ast = RubyNext::Language.parse(contents)
19
- puts ast
data/bin/ruby-next DELETED
@@ -1,16 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- lib_path = File.expand_path("../lib", __dir__)
4
- $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
5
-
6
- require "ruby-next/cli"
7
-
8
- begin
9
- cli = RubyNext::CLI.new
10
- cli.run(ARGV)
11
- rescue => e
12
- raise e if $DEBUG
13
- STDERR.puts e.message
14
- STDERR.puts e.backtrace.join("\n") if ENV["RUBY_NEXT_DEBUG"] == "1"
15
- exit 1
16
- end
data/bin/transform DELETED
@@ -1,21 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- lib = File.expand_path("../../lib", __FILE__)
4
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
-
6
- require "bundler/setup"
7
-
8
- require "ruby-next/language"
9
-
10
- # optional parsers
11
- require "ruby-next/language/rewriters/method_reference"
12
- RubyNext::Language.rewriters << RubyNext::Language::Rewriters::MethodReference
13
-
14
- contents =
15
- if File.exist?(ARGV[0])
16
- File.read(ARGV[0])
17
- else
18
- ARGV[0]
19
- end
20
-
21
- puts RubyNext::Language.transform(contents)
data/lib/ruby-next.rb DELETED
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "ruby-next/version"
4
-
5
- module RubyNext
6
- # Mininum Ruby version supported by RubyNext
7
- MIN_SUPPORTED_VERSION = Gem::Version.new("2.5.0")
8
-
9
- # Where to store transpiled files (relative from the project LOAD_PATH, usually `lib/`)
10
- RUBY_NEXT_DIR = ".rbnext"
11
-
12
- # Defines last minor version for every major version
13
- LAST_MINOR_VERSIONS = {
14
- 2 => 7
15
- }.freeze
16
-
17
- LATEST_VERSION = [2, 7].freeze
18
-
19
- class << self
20
- def next_version(version = RUBY_VERSION)
21
- major, minor = Gem::Version.new(version).segments.map(&:to_i)
22
-
23
- return if major >= LATEST_VERSION.first && minor >= LATEST_VERSION.last
24
-
25
- nxt =
26
- if LAST_MINOR_VERSIONS[major] == minor
27
- "#{major + 1}.0.0"
28
- else
29
- "#{major}.#{minor + 1}.0"
30
- end
31
-
32
- Gem::Version.new(nxt)
33
- end
34
- end
35
-
36
- require_relative "ruby-next/core"
37
- end
data/lib/ruby-next/cli.rb DELETED
@@ -1,94 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "ruby-next"
4
- require "ruby-next/language"
5
-
6
- require "ruby-next/commands/base"
7
- require "ruby-next/commands/nextify"
8
- require "ruby-next/commands/core_ext"
9
-
10
- module RubyNext
11
- # Command line interface for RubyNext
12
- class CLI
13
- class << self
14
- attr_accessor :verbose
15
- end
16
-
17
- self.verbose = false
18
-
19
- COMMANDS = {
20
- "nextify" => Commands::Nextify,
21
- "core_ext" => Commands::CoreExt
22
- }.freeze
23
-
24
- def initialize
25
- end
26
-
27
- def run(args = ARGV)
28
- maybe_print_version(args)
29
-
30
- command = extract_command(args)
31
-
32
- # Handle top-level help
33
- unless command
34
- maybe_print_help
35
- raise "Command must be specified!"
36
- end
37
-
38
- args.delete(command)
39
-
40
- COMMANDS.fetch(command) do
41
- raise "Unknown command: #{command}. Available commands: #{COMMANDS.keys.join(",")}"
42
- end.run(args)
43
- end
44
-
45
- private
46
-
47
- def maybe_print_version(args)
48
- args = args.dup
49
- begin
50
- optparser.parse!(args)
51
- rescue OptionParser::InvalidOption
52
- # skip and pass all args to the command's parser
53
- end
54
- end
55
-
56
- def maybe_print_help
57
- return unless @print_help
58
-
59
- STDOUT.puts optparser.help
60
- exit 0
61
- end
62
-
63
- def extract_command(source_args)
64
- args = source_args.dup
65
- unknown_args = []
66
- command = nil
67
- begin
68
- command, = optparser.permute!(args)
69
- rescue OptionParser::InvalidOption => e
70
- unknown_args += e.args
71
- args = source_args - unknown_args
72
- retry
73
- end
74
- command
75
- end
76
-
77
- def optparser
78
- @optparser ||= begin
79
- OptionParser.new do |opts|
80
- opts.banner = "Usage: ruby-next COMMAND [options]"
81
-
82
- opts.on("-v", "--version", "Print version") do
83
- STDOUT.puts RubyNext::VERSION
84
- exit 0
85
- end
86
-
87
- opts.on("-h", "--help", "Print help") do
88
- @print_help = true
89
- end
90
- end
91
- end
92
- end
93
- end
94
- end
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "optparse"
4
-
5
- module RubyNext
6
- module Commands
7
- class Base
8
- class << self
9
- def run(args)
10
- new(args).run
11
- end
12
- end
13
-
14
- def initialize(args)
15
- parse! args
16
- end
17
-
18
- def parse!(*)
19
- raise NotImplementedError
20
- end
21
-
22
- def run
23
- raise NotImplementedError
24
- end
25
-
26
- def log(msg)
27
- return unless CLI.verbose
28
- $stdout.puts msg
29
- end
30
-
31
- def base_parser
32
- OptionParser.new do |opts|
33
- yield opts
34
-
35
- opts.on("-V", "Turn on verbose mode") do
36
- CLI.verbose = true
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,166 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fileutils"
4
- require "pathname"
5
-
6
- module RubyNext
7
- module Commands
8
- class CoreExt < Base
9
- using RubyNext
10
-
11
- attr_reader :out_path, :min_version, :names, :list, :filter, :original_command
12
- alias list? list
13
-
14
- def run
15
- log "Select core extensions for Ruby v#{min_version}" \
16
- "#{filter ? " and matching #{filter.inspect}" : ""}"
17
-
18
- matching_patches.then do |patches|
19
- next print_list(patches) if list?
20
- generate_core_ext(patches)
21
- end
22
- end
23
-
24
- def parse!(args)
25
- print_help = false
26
- @min_version = MIN_SUPPORTED_VERSION
27
- @original_command = "ruby-next core_ext #{args.join(" ")}"
28
- @names = []
29
- @list = false
30
- @out_path = File.join(Dir.pwd, "core_ext.rb")
31
-
32
- optparser = base_parser do |opts|
33
- opts.banner = "Usage: ruby-next core_ext [options]"
34
-
35
- opts.on("-o", "--output=OUTPUT", "Specify output file or stdout (default: ./core_ext.rb)") do |val|
36
- @out_path = val
37
- end
38
-
39
- opts.on("-l", "--list", "List all available extensions") do
40
- @list = true
41
- end
42
-
43
- opts.on("--min-version=VERSION", "Specify the minimum Ruby version to support") do |val|
44
- @min_version = Gem::Version.new(val)
45
- end
46
-
47
- opts.on("-n", "--name=NAME", "Filter extensions by name") do |val|
48
- names << val
49
- end
50
-
51
- opts.on("-h", "--help", "Print help") do
52
- print_help = true
53
- end
54
- end
55
-
56
- optparser.parse!(args)
57
-
58
- if print_help
59
- $stdout.puts optparser.help
60
- exit 0
61
- end
62
-
63
- @filter = /(#{names.join("|")})/i unless names.empty?
64
- end
65
-
66
- private
67
-
68
- def matching_patches
69
- RubyNext::Core.patches.extensions
70
- .values
71
- .flatten
72
- .filter do |patch|
73
- next if min_version && Gem::Version.new(patch.version) <= min_version
74
- next if filter && !filter.match?(patch.name)
75
- true
76
- end
77
- end
78
-
79
- def print_list(patches)
80
- grouped_patches = patches.group_by(&:version).sort_by(&:first)
81
- grouped_patches.each do |(group, patches)|
82
- $stdout.puts "#{group} extensions:\n"
83
- $stdout.puts patches.sort_by(&:name).map { |patch| " - #{patch.name}" }.join("\n")
84
- $stdout.puts "\n"
85
- end
86
- end
87
-
88
- def generate_core_ext(patches)
89
- grouped_patches = patches.group_by(&:mod).sort_by { |(mod, patch)| mod.singleton_class? ? mod.inspect : mod.name }
90
-
91
- buffer = []
92
-
93
- buffer << "# frozen_string_literal: true\n"
94
-
95
- buffer << generation_meta
96
-
97
- grouped_patches.each do |mod, patches|
98
- singleton = mod.singleton_class?
99
- extend_name = singleton ? patches.first.singleton.name : mod.name
100
- prepend_name = singleton ? "#{patches.first.singleton.name}.singleton_class" : mod.name
101
-
102
- prepended, extended = patches.partition(&:prepend?)
103
-
104
- prepended.map do |patch|
105
- name = "RubyNext::Core::#{patch.name}"
106
-
107
- buffer << <<~RUBY
108
- module #{name}
109
- #{indent_and_trim(patch.body)}
110
- end
111
-
112
- #{prepend_name}.prepend #{name}
113
- RUBY
114
-
115
- name
116
- end
117
-
118
- class_or_module = mod.is_a?(Class) ? "class" : "module"
119
-
120
- buffer << "#{class_or_module} #{extend_name}"
121
-
122
- buffer << " class << self" if singleton
123
-
124
- indent_size = singleton ? 4 : 2
125
-
126
- buffer << extended.map do |patch|
127
- indent_and_trim(patch.body, indent_size)
128
- end.join("\n\n")
129
-
130
- buffer << " end" if singleton
131
-
132
- buffer << "end\n"
133
- end
134
-
135
- contents = buffer.join("\n")
136
-
137
- return $stdout.puts(contents) if out_path == "stdout"
138
-
139
- FileUtils.mkdir_p File.dirname(out_path)
140
- File.write(out_path, contents)
141
-
142
- log "Generated: #{out_path}"
143
- end
144
-
145
- def generation_meta
146
- <<~MSG
147
- # Generated by RubyNext v#{RubyNext::VERSION} using the following command:
148
- #
149
- # #{original_command}
150
- #
151
- MSG
152
- end
153
-
154
- def indent_and_trim(src, size = 2)
155
- new_src = src.dup
156
- # indent code using <size> spaces
157
- new_src.gsub!(/^/, " " * size)
158
- # remove empty lines
159
- new_src.gsub!(/^\s+$/, "")
160
- # remove traling blank lines
161
- new_src.gsub!(/\n\z/, "")
162
- new_src
163
- end
164
- end
165
- end
166
- end