Module: EndlessRuby

Extended by:
EndlessRuby
Included in:
EndlessRuby, Main, Main
Defined in:
lib/endlessruby.rb

Overview

EndlessRubyはRubyをendを取り除いて書けます。

erファイルをrequire

require 'homuhomu.er' | require 'homuhomu'

erファイルを実行

$ path/to/endlessruby.rb homuhomu.er

erファイルをコンパイル

$ path/to/endlessruby.rb -c src/homuhomu.er -o lib
# => src/homuhomu.er をコンパイルして lib/homuhomu.rb を書き出します。
#  -o が省略された場合はカレントディレクトリに書き出します。

Example:

class EndlessRubyWorld

  def self.hello!
    puts "hello!"

[-2, -1, 0, 1, 2].reject do |x|
  x < 0
end.each do |n|
  puts n

Defined Under Namespace

Modules: Main

Constant Summary collapse

VERSION =

EndlessRuby のバージョンです

"0.0.1"

Instance Method Summary collapse

Instance Method Details

#endless_ruby_to_pure_ruby(src) ⇒ Object Also known as: to_pure_ruby, ER2PR, ER2RB

EndlessRubyの構文をピュアなRubyの構文に変換します。


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/endlessruby.rb', line 107

def endless_ruby_to_pure_ruby src
  endless = src.split "\n"

  pure = []
  i = 0
  while i < endless.length
    pure << (currently_line = endless[i])

    if currently_line =~ /(.*)(?:^|(?:(?!\\).))\#(?!\{).*$/
      currently_line = $1
    end

    if blank_line? currently_line
      i += 1
      next
    end

    # ブロックを作らない構文なら単に無視する 
    next i += 1 unless BLOCK_KEYWORDS.any? { |k| k[0] =~ unindent(currently_line)  }

    # ブロックに入る
    keyword = BLOCK_KEYWORDS.each { |k| break k if k[0] =~ unindent(currently_line)  }

    currently_indent_depth = indent_count currently_line
    base_indent_depth = currently_indent_depth

    inner_statements = []
    # def method1
    #   statemetns
    # # document of method2
    # def method2
    #   statements
    # のような場合にコメントの部分はmethod1内に含まないようにする。
    # def method1
    #   statemetns
    # # comment
    #   return
    # のような場合と区別するため。
    comment_count = 0
    in_here_document = nil
    while i < endless.length

      inner_currently_line = endless[i + 1]

      if inner_currently_line =~ /(.*)(?:^|(?:(?!\\).))\#(?!\{).*$/
        if blank_line?($1) && currently_indent_depth >= indent_count(inner_currently_line)
          comment_count += 1
        end
        inner_currently_line = $1
      elsif blank_line? inner_currently_line
        comment_count += 1
      end

      if blank_line? inner_currently_line
        inner_statements << endless[i + 1]
        i += 1
        next
      end

      just_after_indent_depth = indent_count inner_currently_line

      # 次の行がendならば意図のあるものなのでendを持ちあ揚げない
      if inner_currently_line =~ /^\s*end(?!\w).*$/
        comment_count = 0
      end

      if base_indent_depth < just_after_indent_depth
        comment_count = 0
      end

      if in_here_document
        if (in_here_document[0] == '' && inner_currently_line =~ /^#{in_here_document[1]}\s*$/) || # <<DEFINE case
            (in_here_document[0] == '-' && inner_currently_line =~ /^\s*#{in_here_document[1]}\s*$/) # <<-DEFINE case
          in_here_document = nil
          inner_statements << endless[i + 1]
          i += 1
          next
        else
          inner_statements << endless[i + 1]
          i += 1
          next
        end
      end

      if inner_currently_line =~ /^.*?\<\<(\-?)(\w+)(?!\w).*$/
        in_here_document = [$1, $2]
      end

      if base_indent_depth > indent_count(inner_currently_line)
        break
      end

      if base_indent_depth == indent_count(inner_currently_line)
        unless keyword[1..-1].any? { |k| k =~ unindent(inner_currently_line) }
          break
        end
      end

      inner_statements << endless[i + 1]
      i += 1
    end

    # endをコメントより上の行へ持ち上げる
    if 0 < comment_count
      comment_count.times do
        inner_statements.pop
      end
      i -= comment_count
    end

    pure += ER2PR(inner_statements.join("\n")).split "\n"
    # 次の行がendならばendを補完しない(ワンライナーのため)
    unless @decompile
      unless endless[i + 1] && endless[i + 1] =~ /^\s*end(?!\w).*$/
        pure << "#{'  '*currently_indent_depth}end"
      end
    else
      # メソッドチェインは削除しない
      if endless[i + 1] && endless[i + 1] =~ /^\s*end(?:\s|$)\s*$/
        i += 1
      end
    end

    i += 1
  end
  pure.join "\n"
end

#ereval(src, binding = TOPLEVEL_BINDING, filename = __FILE__, lineno = 1) ⇒ Object

文字列をEndlessRubyの構文として実行します。引数の意味はKernel#evalと同じです


86
87
88
89
90
91
92
# File 'lib/endlessruby.rb', line 86

def ereval(src, binding=TOPLEVEL_BINDING, filename=__FILE__, lineno=1)
  at = caller
  eval(ER2PR(src), binding, filename, lineno)
rescue Exception => e
  $@ = at
  raise e
end

#pure_ruby_to_endless_ruby(src) ⇒ Object Also known as: RB2ER, PR2ER

Rubyの構文をEndlessRubyの構文に変換します。


95
96
97
98
99
100
# File 'lib/endlessruby.rb', line 95

def pure_ruby_to_endless_ruby src
  @decompile = true
  s = ER2RB(src)
  @decompile = nil
  s
end