#n ist das anzuzeigende Feld, o die Zwischenablage für eine #Iteration p dient dazu zu jedem Feld die Nachbarschaft zu definieren. n=Array.new o=Array.new p=Array.new x=0 #Anlegen des Arrays n while x<=10000 n[x]=0 x +=1 end #Anlegen des Arrays p x=0 while x<=10000 p[x]=3 x +=1 end n[2]=1 n[102]=1 n[202]=1 loop{ x=0 #Die nachbarschaften aller Felder werden überprüft while x<10000 #a bis f dienen dazu die Nachbarschaft festzulegen. Man stelle sich die #Zahl von 1 bis 64 im Binärcode vor 1 bedeutet an 0 aus a=p[x]/32<1 ? 0 : 1 b=(p[x]%32)/16<1 ? 0 : 1 c=(p[x]%16)/8<1 ? 0 : 1 d=(p[x]%8)/4<1 ? 0 : 1 e=(p[x]%4)/2<1 ? 0 : 1 f=(p[x]%2)<1 ? 0 : 1 #t= n[x-201].to_i*b+n[x-200].to_i*d+n[x-199].to_i*b+ #n[x-102].to_i*a+n[x-101].to_i*e+n[x-100].to_i+n[x-99].to_i*f+n[x-98]#to_i*a+ #n[x-2].to_i*c+n[x-1].to_i+n[x+1].to_i+n[x+2].to_i*c+ #n[x+98].to_i*a+n[x+99].to_i*f+n[x+100].to_i+n[x+101].#to_i*e+n[x+102].to_i*a+ #n[x+199].to_i*b+n[x+200].to_i*d+n[x+201].to_i*b #Die Summe der Felder die zur Nachbarschaft gerechnet werden a bis f #sind hierbei Multiplikatoren mit dem Wert 1oder 0 t=(x-201>=0? n[x-201].to_i : 0)*b+(x-200>=0? n[x-200].to_i : 0)*d+(x-199>=0? n[x-199].to_i : 0)*b+ (x-102>=0? n[x-102].to_i : 0)*a+(x-101>=0?n[x-101].to_i : 0)*e+n[x-100].to_i+(x-99>=0? n[x-99].to_i : 0)*f+(x-98>=0? n[x-98].to_i : 0)*a+ (x-2>=0? n[x-2].to_i : 0)*c+(x-1>=0? n[x-1].to_i : 0)+n[x+1].to_i+n[x+2].to_i*c+ n[x+98].to_i*a+n[x+99].to_i*f+n[x+100].to_i+n[x+101].to_i*e+n[x+102].to_i*a+ n[x+199].to_i*b+n[x+200].to_i*d+n[x+201].to_i*b #Bedingungen wann eine Zelle lebt,stirbt oder geboren wird im Moment #sind die regeln 3 Nachbarn =Geburt und Nachbarn 3,2=Überleben #sonst Tod if t==3 o[x]=1 elsif t==2 and n[x]=1 o[x]=1 else o[x]=0 end x+=1 end #wird überschrieben n=o #und die Ausgabe folgt g=%w{} x=0 while x<100 g[x]=n[100*x+1..100*x+100] x+=1 end x=0 while x<100 puts"#{g[x]}" x+=1 end puts"" sleep(10) } 1E1E1 puts 30.send(:/, 5) # prints 6 "instance variables can be #@included, #@@class_variables and #$globals as well." #%W[ but #@0illegal_values look strange.] %s#ruby allows strange#{constructs}. %s#ruby allows strange#$constructs %s#ruby allows strange#@@constructs %r\VERY STRANGE!\x00 ~%r#
The server encountered an exception and was unable to complete your request.
" self.puts "The exception has provided the following information:
" self.puts "#{exception.class}: #{exception.message} on" self.puts self.puts "#{exception.backtrace.join("\n")}" self.puts "" self.puts "" else self.puts "The server encountered an exception and was unable to complete your request" self.puts "The exception has provided the following information:" self.puts "#{exception.class}: #{exception.message}" self.puts self.puts exception.backtrace.join("\n") end end end if @settings["cache"] buffer = @buffer.join unless @output_started unless @header.has_key?("content-length") self.header("content-length: #{buffer.length}") end sendHeaders end $stdout.print(buffer) elsif !@output_started sendHeaders end @output_allowed = false; # }}} end # Decodes URL encoded data, %20 for example stands for a space. def Rweb.unescape(str) # {{{ if defined? str and str.is_a? String str.gsub!(/\+/, " ") str.gsub(/%.{2}/) do | s | s[1,2].hex.chr end end # }}} end protected def sendHeaders # {{{ Cookie.disallow # no more cookies can be set or modified if !(@settings.has_key?("silent") and @settings["silent"] == true) and !@header.has_key?("x-powered-by") if @mod_ruby header("x-powered-by: #{RWEB} (Ruby/#{RUBY_VERSION}, #{MOD_RUBY})"); else header("x-powered-by: #{RWEB} (Ruby/#{RUBY_VERSION})"); end end if @output_method == "ph" if ((@status == nil or @status == 200) and !@header.has_key?("content-type") and !@header.has_key?("location")) header("content-type: text/html") end if @status != nil $stdout.print "Status: #{@status} #{@reasonPhrase}\r\n" end @header.each do |key, value| key = key *1 # "unfreeze" key :) key[0] = key[0,1].upcase![0] key = key.gsub(/-[a-z]/) do |char| "-" + char[1,1].upcase end $stdout.print "#{key}: #{value}\r\n" end cookies = Cookie.getHttpHeader # Get all cookies as an HTTP Header if cookies $stdout.print cookies end $stdout.print "\r\n" elsif @output_method == "nph" elsif @output_method == "mod_ruby" r = Apache.request if ((@status == nil or @status == 200) and !@header.has_key?("content-type") and !@header.has_key?("location")) header("text/html") end if @status != nil r.status_line = "#{@status} #{@reasonPhrase}" end r.send_http_header @header.each do |key, value| key = key *1 # "unfreeze" key :) key[0] = key[0,1].upcase![0] key = key.gsub(/-[a-z]/) do |char| "-" + char[1,1].upcase end puts "#{key}: #{value.class}" #r.headers_out[key] = value end end @output_started = true # }}} end def getReasonPhrase (status) # {{{ if status == 100 "Continue" elsif status == 101 "Switching Protocols" elsif status == 200 "OK" elsif status == 201 "Created" elsif status == 202 "Accepted" elsif status == 203 "Non-Authoritative Information" elsif status == 204 "No Content" elsif status == 205 "Reset Content" elsif status == 206 "Partial Content" elsif status == 300 "Multiple Choices" elsif status == 301 "Moved Permanently" elsif status == 302 "Found" elsif status == 303 "See Other" elsif status == 304 "Not Modified" elsif status == 305 "Use Proxy" elsif status == 307 "Temporary Redirect" elsif status == 400 "Bad Request" elsif status == 401 "Unauthorized" elsif status == 402 "Payment Required" elsif status == 403 "Forbidden" elsif status == 404 "Not Found" elsif status == 405 "Method Not Allowed" elsif status == 406 "Not Acceptable" elsif status == 407 "Proxy Authentication Required" elsif status == 408 "Request Time-out" elsif status == 409 "Conflict" elsif status == 410 "Gone" elsif status == 411 "Length Required" elsif status == 412 "Precondition Failed" elsif status == 413 "Request Entity Too Large" elsif status == 414 "Request-URI Too Large" elsif status == 415 "Unsupported Media Type" elsif status == 416 "Requested range not satisfiable" elsif status == 417 "Expectation Failed" elsif status == 500 "Internal Server Error" elsif status == 501 "Not Implemented" elsif status == 502 "Bad Gateway" elsif status == 503 "Service Unavailable" elsif status == 504 "Gateway Time-out" elsif status == 505 "HTTP Version not supported" else raise "Unknown Statuscode. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1 for more information." end # }}} end end class Cookie attr_reader :name, :value, :maxage, :path, :domain, :secure, :comment # Sets a cookie. Please see below for details of the attributes. def initialize (name, value = nil, maxage = nil, path = nil, domain = nil, secure = false) # {{{ # HTTP headers (Cookies are a HTTP header) can only set, while no content # is send. So an exception will be raised, when @@allowed is set to false # and a new cookie has set. unless defined?(@@allowed) @@allowed = true end unless @@allowed raise "You can't set cookies after the HTTP headers are send." end unless defined?(@@list) @@list = [] end @@list += [self] unless defined?(@@type) @@type = "netscape" end unless name.class == String raise TypeError, "The name of a cookie must be a string", caller end if value.class.superclass == Integer || value.class == Float value = value.to_s elsif value.class != String && value != nil raise TypeError, "The value of a cookie must be a string, integer, float or nil", caller end if maxage.class == Time maxage = maxage - Time.now elsif !maxage.class.superclass == Integer || !maxage == nil raise TypeError, "The maxage date of a cookie must be an Integer or Time object or nil.", caller end unless path.class == String || path == nil raise TypeError, "The path of a cookie must be nil or a string", caller end unless domain.class == String || domain == nil raise TypeError, "The value of a cookie must be nil or a string", caller end unless secure == true || secure == false raise TypeError, "The secure field of a cookie must be true or false", caller end @name, @value, @maxage, @path, @domain, @secure = name, value, maxage, path, domain, secure @comment = nil # }}} end # Modifies the value of this cookie. The information you want to store. If the # value is nil, the cookie will be deleted by the client. # # This attribute can be a String, Integer or Float object or nil. def value=(value) # {{{ if value.class.superclass == Integer || value.class == Float value = value.to_s elsif value.class != String && value != nil raise TypeError, "The value of a cookie must be a string, integer, float or nil", caller end @value = value # }}} end # Modifies the maxage of this cookie. This attribute defines the lifetime of # the cookie, in seconds. A value of 0 means the cookie should be discarded # imediatly. If it set to nil, the cookie will be deleted when the browser # will be closed. # # Attention: This is different from other implementations like PHP, where you # gives the seconds since 1/1/1970 0:00:00 GMT. # # This attribute must be an Integer or Time object or nil. def maxage=(maxage) # {{{ if maxage.class == Time maxage = maxage - Time.now elsif maxage.class.superclass == Integer || !maxage == nil raise TypeError, "The maxage of a cookie must be an Interger or Time object or nil.", caller end @maxage = maxage # }}} end # Modifies the path value of this cookie. The client will send this cookie # only, if the requested document is this directory or a subdirectory of it. # # The value of the attribute must be a String object or nil. def path=(path) # {{{ unless path.class == String || path == nil raise TypeError, "The path of a cookie must be nil or a string", caller end @path = path # }}} end # Modifies the domain value of this cookie. The client will send this cookie # only if it's connected with this domain (or a subdomain, if the first # character is a dot like in ".ruby-lang.org") # # The value of this attribute must be a String or nil. def domain=(domain) # {{{ unless domain.class == String || domain == nil raise TypeError, "The domain of a cookie must be a String or nil.", caller end @domain = domain # }}} end # Modifies the secure flag of this cookie. If it's true, the client will only # send this cookie if it is secured connected with us. # # The value od this attribute has to be true or false. def secure=(secure) # {{{ unless secure == true || secure == false raise TypeError, "The secure field of a cookie must be true or false", caller end @secure = secure # }}} end # Modifies the comment value of this cookie. The comment won't be send, if # type is "netscape". def comment=(comment) # {{{ unless comment.class == String || comment == nil raise TypeError, "The comment of a cookie must be a string or nil", caller end @comment = comment # }}} end # Changes the type of all cookies. # Allowed values are RFC2109 and netscape (default). def Cookie.type=(type) # {{{ unless @@allowed raise "The cookies are allready send, so you can't change the type anymore." end unless type.downcase == "rfc2109" && type.downcase == "netscape" raise "The type of the cookies must be \"RFC2109\" or \"netscape\"." end @@type = type; # }}} end # After sending this message, no cookies can be set or modified. Use it, when # HTTP-Headers are send. Rweb does this for you. def Cookie.disallow # {{{ @@allowed = false true # }}} end # Returns a HTTP header (type String) with all cookies. Rweb does this for # you. def Cookie.getHttpHeader # {{{ if defined?(@@list) if @@type == "netscape" str = "" @@list.each do |cookie| if cookie.value == nil cookie.maxage = 0 cookie.value = "" end # TODO: Name and value should be escaped! str += "Set-Cookie: #{cookie.name}=#{cookie.value}" unless cookie.maxage == nil expire = Time.now + cookie.maxage expire.gmtime str += "; Expire=#{expire.strftime("%a, %d-%b-%Y %H:%M:%S %Z")}" end unless cookie.domain == nil str += "; Domain=#{cookie.domain}" end unless cookie.path == nil str += "; Path=#{cookie.path}" end if cookie.secure str += "; Secure" end str += "\r\n" end return str else # type == "RFC2109" str = "Set-Cookie: " comma = false; @@list.each do |cookie| if cookie.value == nil cookie.maxage = 0 cookie.value = "" end if comma str += "," end comma = true str += "#{cookie.name}=\"#{cookie.value}\"" unless cookie.maxage == nil str += "; Max-Age=\"#{cookie.maxage}\"" end unless cookie.domain == nil str += "; Domain=\"#{cookie.domain}\"" end unless cookie.path == nil str += "; Path=\"#{cookie.path}\"" end if cookie.secure str += "; Secure" end unless cookie.comment == nil str += "; Comment=\"#{cookie.comment}\"" end str += "; Version=\"1\"" end str end else false end # }}} end end require 'strscan' module BBCode DEBUG = true use 'encoder', 'tags', 'tagstack', 'smileys' =begin The Parser class takes care of the encoding. It scans the given BBCode (as plain text), finds tags and smilies and also makes links of urls in text. Normal text is send directly to the encoder. If a tag was found, an instance of a Tag subclass is created to handle the case. The @tagstack manages tag nesting and ensures valid HTML. =end class Parser class Attribute # flatten and use only one empty_arg def self.create attr attr = flatten attr return @@empty_attr if attr.empty? new attr end private_class_method :new # remove leading and trailing whitespace; concat lines def self.flatten attr attr.strip.gsub(/\n/, ' ') # -> ^ and $ can only match at begin and end now end ATTRIBUTE_SCAN = / (?!$) # don't match at end \s* ( # $1 = key [^=\s\]"\\]* (?: (?: \\. | "[^"\\]*(?:\\.[^"\\]*)*"? ) [^=\s\]"\\]* )* ) (?: = ( # $2 = value [^\s\]"\\]* (?: (?: \\. | "[^"\\]*(?:\\.[^"\\]*)*"? ) [^\s\]"\\]* )* )? )? \s* /x def self.parse source source = source.dup # empty_tag: the tag looks like [... /] # slice!: this deletes the \s*/] at the end # \s+ because [url=http://rubybb.org/forum/] is NOT an empty tag. # In RubyBBCode, you can use [url=http://rubybb.org/forum/ /], and this has to be # interpreted correctly. empty_tag = source.sub!(/^:/, '=') or source.slice!(/\/$/) debug 'PARSE: ' + source.inspect + ' => ' + empty_tag.inspect #-> we have now an attr that's EITHER empty OR begins and ends with non-whitespace. attr = Hash.new attr[:flags] = [] source.scan(ATTRIBUTE_SCAN) { |key, value| if not value attr[:flags] << unescape(key) else next if value.empty? and key.empty? attr[unescape(key)] = unescape(value) end } debug attr.inspect return empty_tag, attr end def self.unescape_char esc esc[1] end def self.unquote qt qt[1..-1].chomp('"').gsub(/\\./) { |esc| unescape_char esc } end def self.unescape str str.gsub(/ (\\.) | (" [^"\\]* (?:\\.[^"\\]*)* "?) /x) { if $1 unescape_char $1 else unquote $2 end } end include Enumerable def each &block @args.each(&block) end attr_reader :source, :args, :value def initialize source @source = source debug 'Attribute#new(%p)' % source @empty_tag, @attr = Attribute.parse source @value = @attr[''].to_s end def empty? self == @@empty_attr end def empty_tag? @empty_tag end def [] *keys res = @attr[*keys] end def flags attr[:flags] end def to_s @attr end def inspect 'ATTR[' + @attr.inspect + (@empty_tag ? ' | empty tag' : '') + ']' end end class Attribute @@empty_attr = new '' end end class Parser def Parser.flatten str # replace mac & dos newlines with unix style str.gsub(/\r\n?/, "\n") end def initialize input = '' # input manager @scanner = StringScanner.new '' # output manager @encoder = Encoder.new @output = '' # tag manager @tagstack = TagStack.new(@encoder) @do_magic = true # set the input feed input end # if you want, you can feed a parser instance after creating, # or even feed it repeatedly. def feed food @scanner.string = Parser.flatten food end # parse through the string using parse_token def parse parse_token until @scanner.eos? @tagstack.close_all @output = parse_magic @encoder.output end def output @output end # ok, internals start here private # the default output functions. everything should use them or the tags. def add_text text = @scanner.matched @encoder.add_text text end # use this carefully def add_html html @encoder.add_html html end # highlights the text as error def add_garbage garbage add_html '' if DEBUG add_text garbage add_html '' if DEBUG end # unknown and incorrectly nested tags are ignored and # sent as plaintext (garbage in - garbage out). # in debug mode, garbage is marked with lime background. def garbage_out start @scanner.pos = start garbage = @scanner.scan(/./m) debug 'GARBAGE: ' + garbage add_garbage garbage end # simple text; everything but [, \[ allowed SIMPLE_TEXT_SCAN_ = / [^\[\\]* # normal* (?: # ( \\.? # special [^\[\\]* # normal* )* # )* /mx SIMPLE_TEXT_SCAN = /[^\[]+/ =begin WHAT IS A TAG? ============== Tags in BBCode can be much more than just a simple [b]. I use many terms here to differ the parts of each tag. Basic scheme: [ code ] TAG START TAG INFO TAG END Most tags need a second tag to close the range it opened. This is done with CLOSING TAGS: [/code] or by using empty tags that have no content and close themselfes: [url=winamp.com /] You surely know this from HTML. These slashes define the TAG KIND = normal|closing|empty and cannot be used together. Everything between [ and ] and expluding the slashes is called the TAG INFO. This info may contain: - TAG ID - TAG NAME including the tag id - attributes The TAG ID is the first char of the info: TAG | ID ----------+---- [quote] | q [±] | & ["[b]"] | " [/url] | u [---] | - As you can see, the tag id shows the TAG TYPE, it can be a normal tag, a formatting tag or an entity. Therefor, the parser first scans the id to decide how to go on with parsing. =end # tag # TODO more complex expression allowing # [quote="[ladico]"] and [quote=\[ladico\]] to be correct tags TAG_BEGIN_SCAN = / \[ # tag start ( \/ )? # $1 = closing tag? ( [^\]] ) # $2 = tag id /x TAG_END_SCAN = / [^\]]* # rest that was not handled \]? # tag end /x CLOSE_TAG_SCAN = / ( [^\]]* ) # $1 = the rest of the tag info ( \/ )? # $2 = empty tag? \]? # tag end /x UNCLOSED_TAG_SCAN = / \[ /x CLASSIC_TAG_SCAN = / [a-z]* /ix SEPARATOR_TAG_SCAN = / \** /x FORMAT_TAG_SCAN = / -- -* /x QUOTED_SCAN = / ( # $1 = quoted text [^"\\]* # normal* (?: # ( \\. # special [^"\\]* # normal* )* # )* ) "? # end quote " /mx ENTITY_SCAN = / ( [^;\]]+ ) # $1 = entity code ;? # optional ending semicolon /ix SMILEY_SCAN = Smileys::SMILEY_PATTERN # this is the main parser loop that separates # text - everything until "[" # from # tags - starting with "[", ending with "]" def parse_token if @scanner.scan(SIMPLE_TEXT_SCAN) add_text else handle_tag end end def handle_tag tag_start = @scanner.pos unless @scanner.scan TAG_BEGIN_SCAN garbage_out tag_start return end closing, id = @scanner[1], @scanner[2] #debug 'handle_tag(%p)' % @scanner.matched handled = case id when /[a-z]/i if @scanner.scan(CLASSIC_TAG_SCAN) if handle_classic_tag(id + @scanner.matched, closing) already_closed = true end end when '*' if @scanner.scan(SEPARATOR_TAG_SCAN) handle_asterisk tag_start, id + @scanner.matched true end when '-' if @scanner.scan(FORMAT_TAG_SCAN) #format = id + @scanner.matched @encoder.add_html "\n
-
can be any combination of <, >, - or whitespace.
#
# === Symbols
#
# Uppercase letters stand for meta symbols, lowercase for terminals.
#
# You can make epsilon-derivations by leaving
empty.
#
# === Example
# S - Ac
# A - Sc
# A - b
# A -
class Grammar
attr_reader :tracer
# Creates a new Grammar.
# If $trace is true, the algorithms explain (textual) what they do to $stdout.
def initialize data, tracer = Tracer.new
@tracer = tracer
@rules = Rules.new
@terminals, @meta_symbols = SortedSet.new, Array.new
@start_symbol = nil
add_rules data
end
attr_reader :meta_symbols, :terminals, :rules, :start_symbol
alias_method :sigma, :terminals
alias_method :alphabet, :terminals
alias_method :variables, :meta_symbols
alias_method :nonterminals, :meta_symbols
# A string representation of the grammar for debugging.
def inspect productions_too = false
'Grammar(meta symbols: %s; alphabet: %s; productions: [%s]; start symbol: %s)' %
[
meta_symbols.join(', '),
terminals.join(', '),
if productions_too
@rules.inspect
else
@rules.size
end,
start_symbol
]
end
# Add rules to the grammar. +rules+ should be a String or respond to +scan+ in a similar way.
#
# Syntax: see Grammar.
def add_rules grammar
@rules = Rules.parse grammar do |rule|
@start_symbol ||= rule.left
@meta_symbols << rule.left
@terminals.merge rule.right.split('').select { |s| terminal? s }
end
@meta_symbols.uniq!
update
end
# Returns a hash acting as FIRST operator, so that
# first["ABC"]
is FIRST(ABC).
# See http://en.wikipedia.org/wiki/LL_parser "Constructing an LL(1) parsing table" for details.
def first
first_operator
end
# Returns a hash acting as FOLLOW operator, so that
# first["A"]
is FOLLOW(A).
# See http://en.wikipedia.org/wiki/LL_parser "Constructing an LL(1) parsing table" for details.
def follow
follow_operator
end
LLError = Class.new(Exception)
LLErrorType1 = Class.new(LLError)
LLErrorType2 = Class.new(LLError)
# Tests if the grammar is LL(1).
def ll1?
begin
for meta in @meta_symbols
first_sets = @rules[meta].map { |alpha| first[alpha] }
first_sets.inject(Set[]) do |already_used, another_first_set|
unless already_used.disjoint? another_first_set
raise LLErrorType1
end
already_used.merge another_first_set
end
if first[meta].include? EPSILON and not first[meta].disjoint? follow[meta]
raise LLErrorType2
end
end
rescue LLError
false
else
true
end
end
private
def first_operator
@first ||= FirstOperator.new self
end
def follow_operator
@follow ||= FollowOperator.new self
end
def update
@first = @follow = nil
end
end
if $0 == __FILE__
eval DATA.read, nil, $0, __LINE__+4
end
require 'test/unit'
class TestCaseGrammar < Test::Unit::TestCase
include Grammar::Symbols
def fifo s
Set[*s.split('')]
end
def test_fifo
assert_equal Set[], fifo('')
assert_equal Set[EPSILON, END_OF_INPUT, 'x', 'Y'], fifo('?xY$')
end
TEST_GRAMMAR_1 = <<-EOG
S - ABCD
A - a
A -
B - b
B -
C - c
C -
D - S
D -
EOG
def test_symbols
assert EPSILON
assert END_OF_INPUT
end
def test_first_1
g = Grammar.new TEST_GRAMMAR_1
f = nil
assert_nothing_raised { f = g.first }
assert_equal(Set['a', EPSILON], f['A'])
assert_equal(Set['b', EPSILON], f['B'])
assert_equal(Set['c', EPSILON], f['C'])
assert_equal(Set['a', 'b', 'c', EPSILON], f['D'])
assert_equal(f['D'], f['S'])
end
def test_follow_1
g = Grammar.new TEST_GRAMMAR_1
f = nil
assert_nothing_raised { f = g.follow }
assert_equal(Set['a', 'b', 'c', END_OF_INPUT], f['A'])
assert_equal(Set['a', 'b', 'c', END_OF_INPUT], f['B'])
assert_equal(Set['a', 'b', 'c', END_OF_INPUT], f['C'])
assert_equal(Set[END_OF_INPUT], f['D'])
assert_equal(Set[END_OF_INPUT], f['S'])
end
TEST_GRAMMAR_2 = <<-EOG
S - Ed
E - EpT
E - EmT
E - T
T - TuF
T - TdF
T - F
F - i
F - n
F - aEz
EOG
def test_first_2
g = Grammar.new TEST_GRAMMAR_2
f = nil
assert_nothing_raised { f = g.first }
assert_equal(Set['a', 'n', 'i'], f['E'])
assert_equal(Set['a', 'n', 'i'], f['F'])
assert_equal(Set['a', 'n', 'i'], f['T'])
assert_equal(Set['a', 'n', 'i'], f['S'])
end
def test_follow_2
g = Grammar.new TEST_GRAMMAR_2
f = nil
assert_nothing_raised { f = g.follow }
assert_equal(Set['m', 'd', 'z', 'p'], f['E'])
assert_equal(Set['m', 'd', 'z', 'p', 'u'], f['F'])
assert_equal(Set['m', 'd', 'z', 'p', 'u'], f['T'])
assert_equal(Set[END_OF_INPUT], f['S'])
end
LLError = Grammar::LLError
TEST_GRAMMAR_3 = <<-EOG
E - TD
D - pTD
D -
T - FS
S - uFS
S -
S - p
F - aEz
F - i
EOG
NoError = Class.new(Exception)
def test_first_3
g = Grammar.new TEST_GRAMMAR_3
# Grammar 3 is LL(1), so all first-sets must be disjoint.
f = nil
assert_nothing_raised { f = g.first }
assert_equal(Set['a', 'i'], f['E'])
assert_equal(Set[EPSILON, 'p'], f['D'])
assert_equal(Set['a', 'i'], f['F'])
assert_equal(Set['a', 'i'], f['T'])
assert_equal(Set[EPSILON, 'u', 'p'], f['S'])
for m in g.meta_symbols
r = g.rules[m]
firsts = r.map { |x| f[x] }.to_set
assert_nothing_raised do
firsts.inject(Set.new) do |already_used, another_first_set|
raise LLError, 'not disjoint!' unless already_used.disjoint? another_first_set
already_used.merge another_first_set
end
end
end
end
def test_follow_3
g = Grammar.new TEST_GRAMMAR_3
# Grammar 3 is not LL(1), because epsilon is in FIRST(S),
# but FIRST(S) and FOLLOW(S) are not disjoint.
f = nil
assert_nothing_raised { f = g.follow }
assert_equal(Set['z', END_OF_INPUT], f['E'])
assert_equal(Set['z', END_OF_INPUT], f['D'])
assert_equal(Set['z', 'p', 'u', END_OF_INPUT], f['F'])
assert_equal(Set['p', 'z', END_OF_INPUT], f['T'])
assert_equal(Set['p', 'z', END_OF_INPUT], f['S'])
for m in g.meta_symbols
first_m = g.first[m]
next unless first_m.include? EPSILON
assert_raise(m == 'S' ? LLError : NoError) do
if first_m.disjoint? f[m]
raise NoError # this is fun :D
else
raise LLError
end
end
end
end
TEST_GRAMMAR_3b = <<-EOG
E - TD
D - pTD
D - PTD
D -
T - FS
S - uFS
S -
F - aEz
F - i
P - p
EOG
def test_first_3b
g = Grammar.new TEST_GRAMMAR_3b
# Grammar 3b is NOT LL(1), since not all first-sets are disjoint.
f = nil
assert_nothing_raised { f = g.first }
assert_equal(Set['a', 'i'], f['E'])
assert_equal(Set[EPSILON, 'p'], f['D'])
assert_equal(Set['p'], f['P'])
assert_equal(Set['a', 'i'], f['F'])
assert_equal(Set['a', 'i'], f['T'])
assert_equal(Set[EPSILON, 'u'], f['S'])
for m in g.meta_symbols
r = g.rules[m]
firsts = r.map { |x| f[x] }
assert_raise(m == 'D' ? LLError : NoError) do
firsts.inject(Set.new) do |already_used, another_first_set|
raise LLError, 'not disjoint!' unless already_used.disjoint? another_first_set
already_used.merge another_first_set
end
raise NoError
end
end
end
def test_follow_3b
g = Grammar.new TEST_GRAMMAR_3b
# Although Grammar 3b is NOT LL(1), the FOLLOW-condition is satisfied.
f = nil
assert_nothing_raised { f = g.follow }
assert_equal(fifo('z$'), f['E'], 'E')
assert_equal(fifo('z$'), f['D'], 'D')
assert_equal(fifo('ai'), f['P'], 'P')
assert_equal(fifo('z$pu'), f['F'], 'F')
assert_equal(fifo('z$p'), f['T'], 'T')
assert_equal(fifo('z$p'), f['S'], 'S')
for m in g.meta_symbols
first_m = g.first[m]
next unless first_m.include? EPSILON
assert_raise(NoError) do
if first_m.disjoint? f[m]
raise NoError # this is fun :D
else
raise LLError
end
end
end
end
def test_ll1?
assert_equal false, Grammar.new(TEST_GRAMMAR_3).ll1?, 'Grammar 3'
assert_equal false, Grammar.new(TEST_GRAMMAR_3b).ll1?, 'Grammar 3b'
end
def test_new
assert_nothing_raised { Grammar.new '' }
assert_nothing_raised { Grammar.new TEST_GRAMMAR_1 }
assert_nothing_raised { Grammar.new TEST_GRAMMAR_2 }
assert_nothing_raised { Grammar.new TEST_GRAMMAR_3 }
assert_nothing_raised { Grammar.new TEST_GRAMMAR_1 + TEST_GRAMMAR_2 + TEST_GRAMMAR_3 }
assert_raise(ArgumentError) { Grammar.new 'S - ?' }
end
end
# vim:foldmethod=syntax
#!/usr/bin/env ruby
require 'fox12'
include Fox
class Window < FXMainWindow
def initialize(app)
super(app, app.appName + ": First Set Calculation", nil, nil, DECOR_ALL, 0, 0, 800, 600, 0, 0)
# {{{ menubar
menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
filemenu = FXMenuPane.new(self)
FXMenuCommand.new(filemenu, "&Start\tCtl-S\tStart the application.", nil, getApp()).connect(SEL_COMMAND, method(:start))
FXMenuCommand.new(filemenu, "&Quit\tAlt-F4\tQuit the application.", nil, getApp(), FXApp::ID_QUIT)
FXMenuTitle.new(menubar, "&File", nil, filemenu)
# }}} menubar
# {{{ statusbar
@statusbar = FXStatusBar.new(self, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|STATUSBAR_WITH_DRAGCORNER)
# }}} statusbar
# {{{ window content
horizontalsplitt = FXSplitter.new(self, SPLITTER_VERTICAL|LAYOUT_SIDE_TOP|LAYOUT_FILL)
@productions = FXList.new(horizontalsplitt, nil, 0, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FIX_HEIGHT|LIST_SINGLESELECT)
@productions.height = 100
@result = FXTable.new(horizontalsplitt, nil, 0, LAYOUT_FILL)
@result.height = 200
@result.setTableSize(2, 2, false)
@result.rowHeaderWidth = 0
header = @result.columnHeader
header.setItemText 0, 'X'
header.setItemText 1, 'FIRST(X)'
for item in header
item.justification = FXHeaderItem::CENTER_X
end
@debug = FXText.new(horizontalsplitt, nil, 0, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|LAYOUT_FIX_HEIGHT)
@debug.height = 200
# }}} window content
end
def load_grammar grammar
@tracer = FirstTracer.new(self)
@grammar = Grammar.new grammar, @tracer
@rules_indexes = Hash.new
@grammar.rules.each_with_index do |rule, i|
@productions.appendItem rule.inspect
@rules_indexes[rule] = i
end
end
def create
super
show(PLACEMENT_SCREEN)
end
def rule rule
@productions.selectItem @rules_indexes[rule]
sleep 0.1
end
def iterate i
setTitle i.to_s
sleep 0.1
end
def missing what
@debug.appendText what + "\n"
sleep 0.1
end
def start sender, sel, pointer
Thread.new do
begin
@grammar.first
rescue => boom
@debug.appendText [boom.to_s, *boom.backtrace].join("\n")
end
end
end
end
$: << 'grammar'
require 'grammar'
require 'first_tracer'
app = FXApp.new("Shinobu", "cYcnus")
# fenster erzeugen
window = Window.new app
unless ARGV.empty?
grammar = File.read(ARGV.first)
else
grammar = <<-EOG1
Z --> S
S --> Sb
S --> bAa
A --> aSc
A --> a
A --> aSb
EOG1
end
window.load_grammar grammar
app.create
app.run
require 'erb'
require 'ftools'
require 'yaml'
require 'redcloth'
module WhyTheLuckyStiff
class Book
attr_accessor :author, :title, :terms, :image, :teaser,
:chapters, :expansion_paks, :encoding, :credits
def [] x
@lang.fetch(x) do
warn warning = "[not translated: '#{x}'!]"
warning
end
end
end
def Book::load( file_name )
YAML::load( File.open( file_name ) )
end
class Section
attr_accessor :index, :header, :content
def initialize( i, h, c )
@index, @header, @content = i, h, RedCloth::new( c.to_s )
end
end
class Sidebar
attr_accessor :title, :content
end
YAML::add_domain_type( 'whytheluckystiff.net,2003', 'sidebar' ) do |taguri, val|
YAML::object_maker( Sidebar, 'title' => val.keys.first, 'content' => RedCloth::new( val.values.first ) )
end
class Chapter
attr_accessor :index, :title, :sections
def initialize( i, t, sects )
@index = i
@title = t
i = 0
@sections = sects.collect do |s|
if s.respond_to?( :keys )
i += 1
Section.new( i, s.keys.first, s.values.first )
else
s
end
end
end
end
YAML::add_domain_type( 'whytheluckystiff.net,2003', 'book' ) do |taguri, val|
['chapters', 'expansion_paks'].each do |chaptype|
i = 0
val[chaptype].collect! do |c|
i += 1
Chapter::new( i, c.keys.first, c.values.first )
end
end
val['teaser'].collect! do |t|
Section::new( 1, t.keys.first, t.values.first )
end
val['terms'] = RedCloth::new( val['terms'] )
YAML::object_maker( Book, val )
end
class Image
attr_accessor :file_name
end
YAML::add_domain_type( 'whytheluckystiff.net,2003', 'img' ) do |taguri, val|
YAML::object_maker( Image, 'file_name' => "i/" + val )
end
end
#
# Convert the book to HTML
#
if __FILE__ == $0
unless ARGV[0]
puts "Usage: #{$0} [/path/to/save/html]"
exit
end
site_path = ARGV[0]
book = WhyTheLuckyStiff::Book::load( 'poignant.yml' )
chapter = nil
# Write index page
index_tpl = ERB::new( File.open( 'index.erb' ).read )
File.open( File.join( site_path, 'index.html' ), 'w' ) do |out|
out << index_tpl.result
end
book.chapters = book.chapters[0,3] if ARGV.include? '-fast'
# Write chapter pages
chapter_tpl = ERB::new( File.open( 'chapter.erb' ).read )
book.chapters.each do |chapter|
File.open( File.join( site_path, "chapter-#{ chapter.index }.html" ), 'w' ) do |out|
out << chapter_tpl.result
end
end
exit if ARGV.include? '-fast'
# Write expansion pak pages
expak_tpl = ERB::new( File.open( 'expansion-pak.erb' ).read )
book.expansion_paks.each do |pak|
File.open( File.join( site_path, "expansion-pak-#{ pak.index }.html" ), 'w' ) do |out|
out << expak_tpl.result( binding )
end
end
# Write printable version
print_tpl = ERB::new( File.open( 'print.erb' ).read )
File.open( File.join( site_path, "print.html" ), 'w' ) do |out|
out << print_tpl.result
end
# Copy css + images into site
copy_list = ["guide.css"] +
Dir["i/*"].find_all { |image| image =~ /\.(gif|jpg|png)$/ }
File.makedirs( File.join( site_path, "i" ) )
copy_list.each do |copy_file|
File.copy( copy_file, File.join( site_path, copy_file ) )
end
end
#!/usr/bin/env ruby
require 'fox'
begin
require 'opengl'
rescue LoadError
require 'fox/missingdep'
MSG = <
# RUBY_VERSION[0].digit == '1.8.2'[0].digit == 1
#
#
#
# ?6.digit == 6
#
#
#
# ?A.digit == 17
#
def digit
self - ?0
end
end
##
# Stellt einen einfachen Scanner fr die lexikalische Analyse der Sprache Pas-0 dar.
#
# @author Andreas Kunert
# Ruby port by murphy
class Scanner
include TokenConsts
attr_reader :line, :pos
# To allow Scanner.new without parameters.
DUMMY_INPUT = 'dummy file'
def DUMMY_INPUT.getc
nil
end
##
# Erzeugt einen Scanner, der als Eingabe das bergebene IO benutzt.
def initialize input = DUMMY_INPUT
@line = 1
@pos = 0
begin
@input = input
@next_char = @input.getc
rescue IOError # TODO show the reason!
Error.ioError
raise
end
end
##
# Liest das n chste Zeichen von der Eingabe.
def read_next_char
begin
@pos += 1
@current_char = @next_char
@next_char = @input.getc
rescue IOError
Error.ioError
raise
end
end
##
# Sucht das n chste Symbol, identifiziert es, instantiiert ein entsprechendes
# PascalSymbol-Objekt und gibt es zurck.
# @see Symbol
# @return das gefundene Symbol als PascalSymbol-Objekt
def get_symbol
current_symbol = nil
until current_symbol
read_next_char
if @current_char.alpha?
identifier = @current_char.chr
while @next_char.alpha? or @next_char.digit?
identifier << @next_char
read_next_char
end
current_symbol = handle_identifier(identifier.upcase)
elsif @current_char.digit?
current_symbol = number
else
case @current_char
when ?\s
# ignore
when ?\n
new_line
when nil
current_symbol = PascalSymbol.new EOP
when ?{
comment
when ?:
if @next_char == ?=
read_next_char
current_symbol = PascalSymbol.new BECOMES
else
current_symbol = PascalSymbol.new COLON
end
when ?<
if (@next_char == ?=)
read_next_char
current_symbol = PascalSymbol.new LEQSY
elsif (@next_char == ?>)
read_next_char
current_symbol = PascalSymbol.new NEQSY
else
current_symbol = PascalSymbol.new LSSSY
end
when ?>
if (@next_char == ?=)
read_next_char
current_symbol = PascalSymbol.new GEQSY
else
current_symbol = PascalSymbol.new GRTSY
end
when ?. then current_symbol = PascalSymbol.new PERIOD
when ?( then current_symbol = PascalSymbol.new LPARENT
when ?, then current_symbol = PascalSymbol.new COMMA
when ?* then current_symbol = PascalSymbol.new TIMES
when ?/ then current_symbol = PascalSymbol.new SLASH
when ?+ then current_symbol = PascalSymbol.new PLUS
when ?- then current_symbol = PascalSymbol.new MINUS
when ?= then current_symbol = PascalSymbol.new EQLSY
when ?) then current_symbol = PascalSymbol.new RPARENT
when ?; then current_symbol = PascalSymbol.new SEMICOLON
else
Error.error(100, @line, @pos) if @current_char > ?\s
end
end
end
current_symbol
end
private
##
# Versucht, in dem gegebenen String ein Schlsselwort zu erkennen.
# Sollte dabei ein Keyword gefunden werden, so gibt er ein PascalSymbol-Objekt zurck, das
# das entsprechende Keyword repr sentiert. Ansonsten besteht die Rckgabe aus
# einem SymbolIdent-Objekt (abgeleitet von PascalSymbol), das den String 1:1 enth lt
# @see symbol
# @return falls Keyword gefunden, zugeh riges PascalSymbol, sonst SymbolIdent
def handle_identifier identifier
if sym = KEYWORD_SYMBOLS[identifier]
PascalSymbol.new sym
else
SymbolIdent.new identifier
end
end
MAXINT = 2**31 - 1
MAXINT_DIV_10 = MAXINT / 10
MAXINT_MOD_10 = MAXINT % 10
##
# Versucht, aus dem gegebenen Zeichen und den folgenden eine Zahl zusammenzusetzen.
# Dabei wird der relativ intuitive Algorithmus benutzt, die endgltige Zahl bei
# jeder weiteren Ziffer mit 10 zu multiplizieren und diese dann mit der Ziffer zu
# addieren. Sonderf lle bestehen dann nur noch in der Behandlung von reellen Zahlen.
# Script size is #{kilosize}" puts "
Last script update: #{last_modif}"
__END__
# DO NOT REMOVE THE PRECEEDING LINE.
# Everything else in this file will be ignored.
#CODE
# @@PLEAC@@_7.7
while line = gets do
# do something with line.
end
# or
while gets do
# do something with $_
end
# or more rubyish
$stdun.each do |line|
# do stuff with line
end
# ARGF may makes this more easy
# this is skipped if ARGV.size==0
ARGV.each do |filename|
# closing and exception handling are done by the block
open(filename) do |fd|
fd.each do |line|
# do stuff with line
end
end rescue abort("can't open %s" % filename)
end
# globbing is done in the Dir module
ARGV = Dir["*.[Cch]"] if ARGV.empty?
# note: optparse is the preferred way to handle this
if (ARGV[0] == '-c')
chop_first += 1
ARGV.shift
end
# processing numerical options
if ARGV[0] =~ /^-(\d+)$/
columns = $1
ARGV.shift
end
# again, better to use optparse:
require 'optparse'
nostdout = 0
append = 0
unbuffer = 0
ignore_ints = 0
ARGV.options do |opt|
opt.on('-n') { nostdout +=1 }
opt.on('-a') { append +=1 }
opt.on('-u') { unbuffer +=1 }
opt.on('-i') { ignore_ints +=1 }
opt.parse!
end or abort("usage: " + __FILE__ + " [-ainu] [filenames]")
# no need to do undef $/, we have File.read
str = File.read(ARGV[0])
# again we have File.read
str = File.read(ARGV[0])
# not sure what this should do:
# I believe open the file, print filename, lineno and line:
ARGF.each_with_index do |line, idx|
print ARGF.filename, ":", idx, ";", line
end
# print all the lines in every file passed via command line that contains login
ARGF.each do |line|
puts line if line =~ /login/
end
#
# even this would fit
#%ruby -ne "print if /f/" 2.log
#
ARGF.each { |l| puts l.downcase! }
#------------------
#!/usr/bin/ruby -p
# just like perl's -p
$_.downcase!
#
# I don't know who should I trust.
# perl's version splits on \w+ while python's on \w.
chunks = 0
File.read(ARGV[0]).split.each do |word|
next if word =~ /^#/
break if ["__DATA__", "__END__"].member? word
chunks += 1
end
print "Found ", chunks, " chunks\n"
# @@PLEAC@@_7.8
old = File.open(old_file)
new = File.open(new_file, "w")
while old.gets do
# change $_, then...
new.print $_
end
old.close
new.close
File.rename(old_file, "old.orig")
File.rename(new_file, old_file)
while old.gets do
if $. == 20 then # we are at the 20th line
new.puts "Extra line 1"
new.puts "Extra line 2"
end
new.print $_
end
while old.gets do
next if 20..30 # skip the 20th line to the 30th
# Ruby (and Perl) permit to write if 20..30
# instead of if (20 <= $.) and ($. <= 30)
new.print $_
end
# @@PLEAC@@_7.9
#% ruby -i.orig -pe 'FILTER COMMAND' file1 file2 file3 ...
#
#-----------------------------
##!/usr/bin/ruby -i.orig -p
# filter commands go here
#-----------------------------
#% ruby -pi.orig -e 'gsub!(/DATE/){Time.now)'
# effectively becomes:
ARGV << 'I'
oldfile = ""
while gets
if ARGF.filename != oldfile
newfile = ARGF.filename
File.rename(newfile, newfile + ".orig")
$stdout = File.open(newfile,'w')
oldfile = newfile
end
gsub!(/DATE/){Time.now}
print
end
$stdout = STDOUT
#-----------------------------
#% ruby -i.old -pe 'gsub!(%r{\bhisvar\b}, 'hervar')' *.[Cchy]
#-----------------------------
# set up to iterate over the *.c files in the current directory,
# editing in place and saving the old file with a .orig extension
$-i = '.orig' # set up -i mode
ARGV.replace(Dir['*.[Cchy]'])
while gets
if $. == 1
print "This line should appear at the top of each file\n"
end
gsub!(/\b(p)earl\b/i, '\1erl') # Correct typos, preserving case
print
ARGF.close if ARGF.eof
end
# @@PLEAC@@_7.10
File.open('itest', 'r+') do |f| # open file for update
lines = f.readlines # read into array of lines
lines.each do |it| # modify lines
it.gsub!(/foo/, 'QQQ')
end
f.pos = 0 # back to start
f.print lines # write out modified lines
f.truncate(f.pos) # truncate to new length
end # file is automatically closed
#-----------------------------
File.open('itest', 'r+') do |f|
out = ""
f.each do |line|
out << line.gsub(/DATE/) {Time.now}
end
f.pos = 0
f.print out
f.truncate(f.pos)
end
# @@PLEAC@@_7.11
File.open('infile', 'r+') do |f|
f.flock File::LOCK_EX
# update file
end
#-----------------------------
File::LOCK_SH # shared lock (for reading)
File::LOCK_EX # exclusive lock (for writing)
File::LOCK_NB # non-blocking request
File::LOCK_UN # free lock
#-----------------------------
unless f.flock File::LOCK_EX | File::LOCK_NB
warn "can't get immediate lock: blocking ..."
f.flock File::LOCK_EX
end
#-----------------------------
File.open('numfile', File::RDWR|File::CREAT) do |f|
f.flock(File::LOCK_EX)
num = f.gets.to_i || 0
f.pos = 0
f.truncate 0
f.puts num + 1q
end
# @@PLEAC@@_7.12
output_handle.sync = true
# Please note that like in Perl, $stderr is already unbuffered
#-----------------------------
#!/usr/bin/ruby -w
# seeme - demo stdio output buffering
$stdout.sync = ARGV.size > 0
print "Now you don't see it..."
sleep 2
puts "now you do"
#-----------------------------
$stderr.sync = true
afile.sync = false
#-----------------------------
# assume 'remote_con' is an interactive socket handle,
# but 'disk_file' is a handle to a regular file.
remote_con.sync = true # unbuffer for clarity
disk_file.sync = false # buffered for speed
#-----------------------------
require 'socket'
sock = TCPSocket.new('www.ruby-lang.org', 80)
sock.sync = true
sock.puts "GET /en/ HTTP/1.0 \n\n"
resp = sock.read
print "DOC IS: #{resp}\n"
# @@PLEAC@@_7.13
#-----------------------------
# assumes fh1, fh2, fh2 are oen IO objects
nfound = select([$stdin, fh1, fh2, fh3], nil, nil, 0)
nfound[0].each do |file|
case file
when fh1
# do something with fh1
when fh2
# do something with fh2
when fh3
# do something with fh3
end
end
#-----------------------------
input_files = []
# repeat next line for all in-files to poll
input_files << fh1
if nfound = select(input_files, nil, nil, 0)
# input ready on files in nfound[0]
end
# @@PLEAC@@_8.0
#-----------------------------
# datafile is a file or IO object
datafile.readlines.each { |line|
line.chomp!
size = line.length
puts size
}
#-----------------------------
datafile.readlines.each { |line|
puts line.chomp!.length
}
#-----------------------------
lines = datafile.readlines
#-----------------------------
whole_file = file.read
#-----------------------------
# ruby -040 -e 'word = gets; puts "First word is #{word}"'
#-----------------------------
# ruby -ne 'BEGIN { $/="%%\n" }; $_.chomp; puts $_ if( $_=~/Unix/i)' fortune.dat
#-----------------------------
handle.print "one", "two", "three" # "onetwothree"
puts "Baa baa black sheep." # sent to $stdout
#-----------------------------
buffer = handle.read(4096)
rv = buffer.length
#-----------------------------
handle.truncate(length)
open("/tmp#{$$}.pid", 'w') { |handle| handle.truncate(length) }
#-----------------------------
pos = datafile.pos # tell is an alias of pos
puts "I'm #{pos} bytes from the start of datafile"
#-----------------------------
logfile.seek(0, IO::SEEK_END)
datafile.seek(pos) # IO::SEEK_SET is the default
out.seek(-20, IO::SEEK_CUR)
#-----------------------------
written = datafile.syswrite(mystring)
raise RunTimeError unless written == mystring.length
block = infile.sysread(256) # no equivalent to perl offset parameter in sysread
puts "only read #{block.length} bytes" if 256 != block.length
#-----------------------------
pos = handle.sysseek(0, IO::SEEK_CUR) # don't change position
# @@PLEAC@@_8.1
while (line = fh.gets)
line.chomp!
nextline = nil
line.gsub!(/\\$/) { |match| nextline = fh.gets; '' }
if (nextline != nil)
line += nextline
redo
end
# process full record in line here
end
#-----------------------------
# DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) \
# $(TEXINFOS) $(INFOS) $(MANS) $(DATA)
# DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) \
# $(TEXINFOS) $(INFO_DEPS) $(MANS) $(DATA) \
# $(EXTRA_DIST)
#-----------------------------
line.gsub!(/\\\s*$/, '') {
# as before
}
# @@PLEAC@@_8.2
#-----------------------------
count = `wc -l < #{filename}`
fail "wc failed: #{$?}" if $? != 0
count.chomp!
#-----------------------------
count = 0
File.open(file, 'r') { |fh|
count += 1 while fh.gets
}
# count now holds the number of lines read
#-----------------------------
count = 0
while (chunk = file.sysread(2**16))
count += chunk.count("\n")
end rescue EOFError
#-----------------------------
File.open(filename,'r') { |fh|
count += 1 while fh.gets
}
# count now holds the number of lines read
#-----------------------------
# As ruby doesn't quite have an equivalent to using a for
# statement as in perl, I threw this in
count = File.readlines(filename).size
#-----------------------------
1 while file.gets
count = $.
#-----------------------------
$/ = ''
open(filename, 'r') { |fh|
1 while fh.gets
para_count = $.
} rescue fail("can't open #{filename}: $!")
#-----------------------------
# ^^PLEAC^^_8.3
#-----------------------------
while (gets)
split.each { |chunk|
# do something with chunk
}
end
#-----------------------------
while (gets)
gsub(/(\w[\w'-]*)/) { |word|
# do something with word
}
end
#-----------------------------
# Make a word frequency count
# normally hashes can be created using {} or just Hash.new
# but we want the default value of an entry to be 0 instead
# of nil. (nil can't be incremented)
seen = Hash.new(0)
while (gets)
gsub(/(\w[\w'-]*)/) { |word|
seen[word.downcase] += 1
}
end
# output hash in a descending numeric sort of its values
seen.sort { |a,b| b[1] <=> a[1] }.each do |k,v|
printf("%5d %s\n", v, k )
end
#-----------------------------
# Line frequency count
seen = Hash.new(0)
while (gets)
seen[$_.downcase] += 1
end
seen.sort { |a,b| b[1] <=> a[1] }.each do |k,v|
printf("%5d %s\n", v, k )
end
#-----------------------------
# @@PLEAC@@_8.4
#-----------------------------
# instead of file handle FILE, we can just
# use a string containing the filename
File.readlines(file).each { |line|
# do something with line
}
#-----------------------------
File.readlines(file).reverse_each { |line|
# do something with line
}
#-----------------------------
# the variable lines might have been created
# this way
# lines = File.readlines(file)
#
# normally one would use the reverse_each, but
# if you insist on using a numerical index to
# iterate over the lines array...
(lines.size - 1).downto(0) { |i|
line = lines[i]
}
#-----------------------------
# the second readlines argument is a the
# record separator $/, just like perl, a blank
# separator splits the records into paragraphs
File.readlines(file, '').each { |paragraph|
# do something with paragraph
puts "->Paragraph #{paragraph}"
}
#-----------------------------
# @@PLEAC@@_8.6
$/ = "%\n";
srand;
File.open('/usr/share/fortune/humorists').each do |line|
adage = line if rand($.) < 1
end
puts adage;
# @@PLEAC@@_8.10
begin
fh = File.open(file, "r+")
addr = fh.tell unless fh.eof while fh.gets
fh.truncate(addr)
rescue SystemCallError
$stderr.puts "#$!"
end
# @@PLEAC@@_9.0
entry = File.stat("/usr/bin/vi")
entry = File.stat("/usr/bin")
entry = File.stat(INFILE)
entry = File.stat("/usr/bin/vi")
ctime = entry.ctime
size = entry.size
f = File.open(filename, "r")
## There is no -T equivalent in Ruby, but we can still test emptiness
if test(?s, filename)
puts "#{filename} doesn't have text in it."
exit
end
Dir.new("/usr/bin").each do |filename|
puts "Inside /usr/bin is something called #{filename}"
end
# @@PLEAC@@_9.1
file = File.stat("filename")
readtime, writetime = file.atime, file.mtime
file.utime(readtime, writetime)
SECONDS_PER_DAY = 60 * 60 * 24
file = File.stat("filename")
atime, mtime = file.atime, file.mtime
atime -= 7 * SECONDS_PER_DAY
mtime -= 7 * SECONDS_PER_DAY
File.utime(atime, mtime, file)
mtime = File.stat(file).mtime
File.utime(Time.new, mtime, file)
File.utime(Time.new, File.stat("testfile").mtime, file)
#-----------------------------
#!/usr/bin/ruby -w
## uvi - vi a file without changing it's access times
if ARGV.length != 1
puts "usage: uvi filename"
exit
end
file = ARGV[0]
atime, mtime = File.stat(file).atime, File.stat(file).mtime
system(ENV["EDITOR"] || "vi", file)
File.utime(atime, mtime, file)
#-----------------------------
# @@PLEAC@@_9.2
File.unlink(FILENAME)
err_flg = false
filenames.each do |file|
begin
File.unlink(file)
rescue
err_flg = $!
end
end
err_flg and raise "Couldn't unlink all of #{filenames.join(" ")}: #{err_flg}"
File.unlink(file)
count = filenames.length
filenames.each do |file|
begin
File.unlink(file)
rescue
count -= 1
end
end
if count != filenames.length
STDERR.puts "could only delete #{count} of #{filenames.length} files"
end
# @@PLEAC@@_9.3
require "ftools"
File.copy(oldfile, newfile)
infile = File.open(oldfile, "r")
outfile = File.open(newfile, "w")
blksize = infile.stat.blksize
# This doesn't handle partial writes or ^Z
# like the Perl version does.
while (line = infile.read(blksize))
outfile.write(line)
end
infile.close
outfile.close
system("cp #{oldfile} #{newfile}") # unix
system("copy #{oldfile} #{newfile}") # dos, vms
require "ftools"
File.copy("datafile.dat", "datafile.bak")
File.move("datafile.new", "datafile.dat")
# @@PLEAC@@_9.4
$seen = {} # must use global var to be seen inside of method below
def do_my_thing(filename)
dev, ino = File.stat(filename).dev, File.stat(filename).ino
unless $seen[[dev, ino]]
# do something with $filename because we haven't
# seen it before
end
$seen[[dev, ino]] = $seen[[dev, ino]].to_i + 1
end
files.each do |filename|
dev, ino = File.stat(filename).dev, File.stat(filename).ino
if !$seen.has_key?([dev, ino])
$seen[[dev, ino]] = []
end
$seen[[dev, ino]].push(filename)
end
$seen.keys.sort.each do |devino|
ino, dev = devino
if $seen[devino].length > 1
# $seen[devino] is a list of filenames for the same file
end
end
# @@PLEAC@@_9.5
Dir.open(dirname) do |dir|
dir.each do |file|
# do something with dirname/file
puts file
end
end
# Dir.close is automatic
# No -T equivalent in Ruby
dir.each do |file|
next if file =~ /^\.\.?$/
# ...
end
def plainfiles(dir)
dh = Dir.open(dir)
dh.entries.grep(/^[^.]/).
map {|file| "#{dir}/#{file}"}.
find_all {|file| test(?f, file)}.
sort
end
# @@PLEAC@@_9.6
list = Dir.glob("*.c")
dir = Dir.open(path)
files = dir.entries.grep(/\.c$/)
dir.close
files = Dir.glob("*.c")
files = Dir.open(path).entries.grep(/\.[ch]$/i)
dir = Dir.new(path)
files = dir.entries.grep(/\.[ch]$/i)
begin
d = Dir.open(dir)
rescue Errno::ENOENT
raise "Couldn't open #{dir} for reading: #{$!}"
end
files = []
d.each do |file|
puts file
next unless file =~ /\.[ch]$/i
filename = "#{dir}/#{file}"
# There is no -T equivalent in Ruby, but we can still test emptiness
files.push(filename) if test(?s, filename)
end
dirs.entries.grep(/^\d+$/).
map { |file| [file, "#{path}/#{file}"]} .
select { |file| test(?d, file[1]) }.
sort { |a,b| a[0] <=> b[0] }.
map { |file| file[1] }
# @@PLEAC@@_9.7
require 'find'
Find.find(dirlist) do |file|
# do whatever
end
require 'find'
argv = ARGV.empty? ? %w{.} : ARGV
Find.find(*argv) do |file|
print file, (test(?d, file) ? "/\n" : "\n")
end
require 'find'
argv = ARGV.empty? ? %w{.} : ARGV
sum = 0
Find.find(*argv) do |file|
size = test(?s, file) || 0
sum += size
end
puts "#{argv.join(' ')} contains #{sum} bytes"
require 'find'
argv = ARGV.empty? ? %w{.} : ARGV
saved_size, saved_name = -1, ""
Find.find(*argv) do |file|
size = test(?s, file) || 0
next unless test(?f, file) && size > saved_size
saved_size = size
saved_name = file
end
puts "Biggest file #{saved_name} in #{argv.join(' ')} is #{saved_size}"
require 'find'
argv = ARGV.empty? ? %w{.} : ARGV
age, name = nil
Find.find(*argv) do |file|
mtime = File.stat(file).mtime
next if age && age > mtime
age = mtime
name = file
end
puts "#{name} #{age}"
#-----------------------------
#!/usr/bin/ruby -w
# fdirs - find all directories
require 'find'
argv = ARGV.empty? ? %w{.} : ARGV
File.find(*argv) { |file| puts file if test(?d, file) }
#-----------------------------
# @@PLEAC@@_9.8
require 'fileutils'
puts "Usage #{$0} dir ..." if ARGV.empty?
ARGV.each do |dir|
FileUtils.rmtree(dir)
end
# @@PLEAC@@_9.9
require 'ftools'
names.each do |file|
newname = file
begin
File.move(file, newname)
rescue Errno::EPERM
$stderr.puts "Couldn't rename #{file} to #{newname}: #{$!}"
end
end
require 'ftools'
op = ARGV.empty? ? (raise "Usage: rename expr [files]\n") : ARGV.shift
argv = ARGV.empty? ? $stdin.readlines.map { |f| f.chomp } : ARGV
argv.each do |file|
was = file
file = eval("file.#{op}")
File.move(was, file) unless was == file
end
# @@PLEAC@@_9.10
base = File.basename(path)
dir = File.dirname(path)
# ruby has no fileparse equivalent
dir, base = File.split(path)
ext = base.scan(/\..*$/).to_s
path = '/usr/lib/libc.a'
file = File.basename(path)
dir = File.dirname(path)
puts "dir is #{dir}, file is #{file}"
# dir is /usr/lib, file is libc.a
path = '/usr/lib/libc.a'
dir, filename = File.split(path)
name, ext = filename.split(/(?=\.)/)
puts "dir is #{dir}, name is #{name}, ext is #{ext}"
# NOTE: The Ruby code prints
# dir is /usr/lib, name is libc, extension is .a
# while the Perl code prints a '/' after the directory name
# dir is /usr/lib/, name is libc, extension is .a
# No fileparse_set_fstype() equivalent in ruby
def extension(path)
ext = path.scan(/\..*$/).to_s
ext.sub(/^\./, "")
end
# @@PLEAC@@_9.11
#-----------------------------
#!/usr/bin/ruby -w
# symirror - build spectral forest of symlinks
require 'find'
require 'fileutils'
raise "usage: #{$0} realdir mirrordir" unless ARGV.size == 2
srcdir,dstdir = ARGV
srcmode = File::stat(srcdir).mode
Dir.mkdir(dstdir, srcmode & 07777) unless test(?d, dstdir)
# fix relative paths
Dir.chdir(srcdir) {srcdir = Dir.pwd}
Dir.chdir(dstdir) {dstdir = Dir.pwd}
Find.find(srcdir) do |srcfile|
if test(?d, srcfile)
dest = srcfile.sub(/^#{srcdir}/, dstdir)
dmode = File::stat(srcfile).mode & 07777
Dir.mkdir(dest, dmode) unless test(?d, dest)
a = Dir["#{srcfile}/*"].reject{|f| test(?d, f)}
FileUtils.ln_s(a, dest)
end
end
# @@PLEAC@@_9.12
# we use the Getopt/Declare library here for convenience:
# http://raa.ruby-lang.org/project/getoptdeclare/
#-----------------------------
#!/usr/bin/ruby -w
# lst - list sorted directory contents (depth first)
require 'find'
require 'etc'
require "Getopt/Declare"
# Note: in the option-spec below there must by at least one hard
# tab in between each -option and its description. For example
# -i