diff options
author | gbrandl <devnull@localhost> | 2006-10-30 08:58:16 +0100 |
---|---|---|
committer | gbrandl <devnull@localhost> | 2006-10-30 08:58:16 +0100 |
commit | 774af50b54d2ada20167b8b11a63d077b41ca5a9 (patch) | |
tree | 63876f260526e4aa78c5bebb758efbdef55e9ca9 /tests/examplefiles/example.rb | |
parent | c42b7e1df1a4bcd5107b2a118b74d8dd476b0223 (diff) | |
download | pygments-774af50b54d2ada20167b8b11a63d077b41ca5a9.tar.gz |
[svn] Add a new unit test, reduce size of some examples, fix a few errors.
Diffstat (limited to 'tests/examplefiles/example.rb')
-rw-r--r-- | tests/examplefiles/example.rb | 2514 |
1 files changed, 0 insertions, 2514 deletions
diff --git a/tests/examplefiles/example.rb b/tests/examplefiles/example.rb index 53c89efe..8a3304ba 100644 --- a/tests/examplefiles/example.rb +++ b/tests/examplefiles/example.rb @@ -7554,2517 +7554,3 @@ trunc_em(nums) # ``chomp'' chomps the record separator and returns what's expected # ``chomp!'' does the same but also modifies the parameter object - -# @@PLEAC@@_10.2 -def somefunc - variable = something # variable is local by default -end - -name, age = ARGV -start = fetch_time - -a, b = pair # will succeed if pair is an Array object (like ARGV is) -c = fetch_time - -# In ruby, run_check can't access a, b, or c until they are -# explicitely defined global (using leading $), even if they are -# both defined in the same scope - -def check_x(x) - y = "whatever" - run_check - if $condition - puts "got $x" - end -end - -# The following will keep a reference to the array, though the -# results will be slightly different from perl: the last element -# of $global_array will be itself an array -def save_array(ary) - $global_array << ary -end - -# The following gives the same results as in Perl for $global_array, -# though it doesn't illustrate anymore the way to keep a reference -# to an object: $global_array is extended with the elements of ary -def save_array(ary) - $global_array += ary -end - - -# @@PLEAC@@_10.3 -# In Ruby, AFAIK a method cannot access "local variables" defined -# upper scope; mostly because everything is an object, so you'll -# do the same by defining an attribute or a static attribute - -# In Ruby the BEGIN also exists: -BEGIN { puts "hello from BEGIN" } -puts "hello from main" -BEGIN { puts "hello from 2nd BEGIN" } -# gives: -# hello from BEGIN -# hello from 2nd BEGIN -# hello from main - -# In Ruby, it can be written as a static method and a static -# variable -class Counter - @@counter = 0 - def Counter.next_counter; @@counter += 1; end -end - -# There is no need of BEGIN since the variable will get -# initialized when parsing -class Counter - @@counter = 42 - def Counter.next_counter; @@counter += 1; end - def Counter.prev_counter; @@counter -= 1; end -end - - -# @@PLEAC@@_10.4 -# You can either get the whole trace as an array of strings, each -# string telling which file, line and method is calling: -caller - -# ...or only the last caller -caller[0] - -# We need to extract just the method name of the backtrace: -def whoami; caller()[0] =~ /in `([^']+)'/ ? $1 : '(anonymous)'; end -def whowasi; caller()[1] =~ /in `([^']+)'/ ? $1 : '(anonymous)'; end - - -# @@PLEAC@@_10.5 -# In Ruby, every value is a reference on an object, thus there is -# no such problem -array_diff(array1, array2) - -def add_vecpair(a1, a2) - results = [] - a1.each_index { |i| results << (a1[i] + a2[i]) } - results -end -a = [1, 2] -b = [5, 8] -c = add_vecpair(a, b) -p c - -# Add this to the beginning of the function to check if we were -# given two arrays -a1.type == Array && a2.type == Array or - raise "usage: add_vecpair array1 array2 (was used with: #{a1.type} #{a2.type})" - - -# @@PLEAC@@_10.6 -# There is no return context in Ruby - - -# @@PLEAC@@_10.7 -# Like in Perl, we need to fake with a hash, but it's dirty :-( -def thefunc(param_args) - args = { 'INCREMENT' => '10s', 'FINISH' => '0', 'START' => 0 } - args.update(param_args) - if (args['INCREMENT'] =~ /m$/ ) - # ..... - end -end - -thefunc({ 'INCREMENT' => '20s', 'START' => '+5m', 'FINISH' => '+30m' }) -thefunc({}) - - -# @@PLEAC@@_10.8 -# there is no "undef" direct equivalent but there is the slice equiv: -a, c = func.indexes(0, 2) - - -# @@PLEAC@@_10.9 -# Ruby has no such limitation: -def somefunc - ary = [] - hash = {} - # ... - return ary, hash -end -arr, dict = somefunc - -array_of_hashes = fn -h1, h2, h3 = fn - - -# @@PLEAC@@_10.10 -return -# or (equivalent) -return nil - - -# @@PLEAC@@_10.11 -# You can't prototype in Ruby regarding types :-( -# Though, you can force the number of arguments: -def func_with_no_arg; end -def func_with_no_arg(); end -def func_with_one_arg(a1); end -def func_with_two_args(a1, a2); end -def func_with_any_number_of_args(*args); end - - -# @@PLEAC@@_10.12 -raise "some message" # raise exception - -begin - val = func -rescue Exception => msg - $stderr.puts "func raised an exception: #{msg}" -end - -# In Ruby the rescue statement uses an exception class, every -# exception which is not matched is still continuing -begin - val = func -rescue FullMoonError - ... -end - - -# @@PLEAC@@_10.13 -# Saving Global Values -# Of course we can just save the value and restore it later: -def print_age - puts "Age is #{$age}" -end - -$age = 18 # global variable -print_age() -if condition - safeage = $age - $age = 23 - print_age() - $age = safeage -end - -# We can also use a method that saves the global variable and -# restores it automatically when the block is left: - -def local(var) - eval("save = #{var.id2name}") - begin - result = yield - ensure - # we want to call this even if we got an exception - eval("#{var.id2name} = save") - end - result -end - -condition = true -$age = 18 -print_age() -if condition - local(:$age) { - $age = 23 - print_age() - } -end -print_age() - -# There is no need to use local() for filehandles or directory -# handles in ruby because filehandles are normal objects. - - -# @@PLEAC@@_10.14 -# In Ruby you may redefine a method [but not overload it :-(] -# just by defining again with the same name. -def foo; puts 'foo'; end -def foo; puts 'bar'; end -foo -#=> bar - -# You can also take a reference to an existing method before -# redefining a new one, using the `alias' keyword -def foo; puts 'foo'; end -alias foo_orig foo -def foo; puts 'bar'; end -foo_orig -foo -#=> foo -#=> bar - -# AFAIK, there is no direct way to create a new method whose name -# comes from a variable, so use "eval" -colors = %w(red blue green yellow orange purple violet) -colors.each { |c| - eval <<-EOS - def #{c}(*a) - "<FONT COLOR='#{c}'>" + a.to_s + "</FONT>" - end - EOS -} - - -# @@PLEAC@@_10.15 -def method_missing(name, *args) - "<FONT COLOR='#{name}'>" + args.join(' ') + "</FONT>" -end -puts chartreuse("stuff") - - -# @@PLEAC@@_10.16 -def outer(arg) - x = arg + 35 - inner = proc { x * 19 } - x + inner.call() -end - - -# @@PLEAC@@_10.17 -#!/usr/bin/ruby -w -# mailsort - sort mbox by different criteria -require 'English' -require 'Date' - -# Objects of class Mail represent a single mail. -class Mail - attr_accessor :no - attr_accessor :subject - attr_accessor :fulltext - attr_accessor :date - - def initialize - @fulltext = "" - @subject = "" - end - - def append(para) - @fulltext << para - end - - # this is called if you call puts(mail) - def to_s - @fulltext - end -end - -# represents a list of mails. -class Mailbox < Array - - Subjectpattern = Regexp.new('Subject:\s*(?:Re:\s*)*(.*)\n') - Datepattern = Regexp.new('Date:\s*(.*)\n') - - # reads mails from open file and stores them - def read(file) - $INPUT_RECORD_SEPARATOR = '' # paragraph reads - msgno = -1 - file.each { |para| - if para =~ /^From/ - mail = Mail.new - mail.no = (msgno += 1) - md = Subjectpattern.match(para) - if md - mail.subject = md[1] - end - md = Datepattern.match(para) - if md - mail.date = DateTime.parse(md[1]) - else - mail.date = DateTime.now - end - self.push(mail) - end - mail.append(para) if mail - } - end - - def sort_by_subject_and_no - self.sort_by { |m| - [m.subject, m.no] - } - end - - # sorts by a list of attributs of mail, given as symbols - def sort_by_attributs(*attrs) - # you can sort an Enumerable by an array of - # values, they would be compared - # from ary[0] to ary[n]t, say: - # ['b',1] > ['a',10] > ['a',9] - self.sort_by { |elem| - attrs.map { |attr| - elem.send(attr) - } - } - end - -end - -mailbox = Mailbox.new -mailbox.read(ARGF) - -# print only subjects sorted by subject and number -for m in mailbox.sort_by_subject_and_no - puts(m.subject) -end - -# print complete mails sorted by date, then subject, then number -for m in mailbox.sort_by_attributs(:date, :subject) - puts(m) -end - - -# @@PLEAC@@_11.7 -def mkcounter(count) - start = count - bundle = { - "NEXT" => proc { count += 1 }, - "PREV" => proc { count -= 1 }, - "RESET" => proc { count = start } - } - bundle["LAST"] = bundle["PREV"] - return bundle -end - -c1 = mkcounter(20) -c2 = mkcounter(77) - -puts "next c1: #{c1["NEXT"].call}" # 21 -puts "next c2: #{c2["NEXT"].call}" # 78 -puts "next c1: #{c1["NEXT"].call}" # 22 -puts "last c1: #{c1["PREV"].call}" # 21 -puts "last c1: #{c1["LAST"].call}" # 20 -puts "old c2: #{c2["RESET"].call}" # 77 - - -# @@PLEAC@@_11.15 -class Binary_tree - def initialize(val) - @value = val - @left = nil - @right = nil - end - - # insert given value into proper point of - # provided tree. If no tree provided, - # use implicit pass by reference aspect of @_ - # to fill one in for our caller. - def insert(val) - if val < @value then - if @left then - @left.insert(val) - else - @left = Binary_tree.new(val) - end - elsif val > @value then - if @right then - @right.insert(val) - else - @right = Binary_tree.new(val) - end - else - puts "double" - # do nothing, no double values - end - end - - # recurse on left child, - # then show current value, - # then recurse on right child. - def in_order - @left.in_order if @left - print @value, " " - @right.in_order if @right - end - - # show current value, - # then recurse on left child, - # then recurse on right child. - def pre_order - print @value, " " - @left.pre_order if @left - @right.pre_order if @right - end - - # recurse on left child, - # then recurse on right child, - # then show current value. - def post_order - @left.post_order if @left - @right.post_order if @right - print @value, " " - end - - # find out whether provided value is in the tree. - # if so, return the node at which the value was found. - # cut down search time by only looking in the correct - # branch, based on current value. - def search(val) - if val == @value then - return self - elsif val < @value then - return @left.search(val) if @left - return nil - else - return @right.search(val) if @right - return nil - end - end -end - -# first generate 20 random inserts -test = Binary_tree.new(0) -for a in 0..20 - test.insert(rand(1000)) -end - -# now dump out the tree all three ways -print "Pre order: "; test.pre_order; puts "" -print "In order: "; test.in_order; puts "" -print "Post order: "; test.post_order; puts "" - -print "search?" -while gets - print test.search($_.to_i) - print "\nsearch?" -end - - -# @@PLEAC@@_12.0 -# class and module names need to have the first letter capitalized -module Alpha - NAME = 'first' -end -module Omega - NAME = 'last' -end -puts "Alpha is #{Alpha::NAME}, Omega is #{Omega::NAME}" - -# ruby doesn't differentiate beteen compile-time and run-time -require 'getoptlong.rb' -require 'getoptlong' # assumes the .rb -require 'cards/poker.rb' -require 'cards/poker' # assumes the .rb -load 'cards/poker' # require only loads the file once - -module Cards - module Poker - @card_deck = Array.new # or @card_deck = [] - def shuffle - end - end -end - - -# @@PLEAC@@_12.1 -# a module exports all of its functions -module Your_Module - def self.function - # this would be called as Your_Module.function - end - - def Your_Module.another - # this is the same as above, but more specific - end -end - -# @@PLEAC@@_12.2 -begin - require 'nonexistent' -rescue LoadError - puts "Couldn't load #{$!}" # $! contains the last error string -end - -# @@PLEAC@@_12.4 -# module variables are private unless access functions are defined -module Alpha - @aa = 10 - @bb = 11 - - def self.put_aa - puts @aa - end - - def self.bb=(val) - @bb = val - end -end - -Alpha.bb = 12 -# Alpha.aa = 10 # error, no aa=method - - -# @@PLEAC@@_12.5 -# caller provides a backtrace of the call stack -module MyModule - def find_caller - caller - end - - def find_caller2(i) - caller(i) # an argument limits the size of the stack returned - end -end - - -# @@PLEAC@@_12.6 -BEGIN { - $logfile = '/tmp/mylog' unless defined? $logfile - $LF = File.open($logfile, 'a') -} - -module Logger - def self.logmsg(msg) - $LF.puts msg - end - - logmsg('startup') -end - -END { - Logger::logmsg('shutdown') - $LF.close -} - - -# @@PLEAC@@_12.7 -#----------------------------- -# results may be different on your system -# % ruby -e "$LOAD_PATH.each_index { |i| printf("%d %s\n", i, $LOAD_PATH[i] } -#0 /usr/local/lib/site_ruby/1.6 -#1 /usr/local/lib/site_ruby/1.6/i386-linux -#2 /usr/local/lib/site_ruby/ -#3 /usr/lib/ruby/1.6 -#4 /usr/lib/ruby/1.6/i136-linux -#5 . -#----------------------------- -# syntax for sh, bash, ksh, or zsh -#$ export RUBYLIB=$HOME/rubylib - -# syntax for csh or tcsh -# % setenv RUBYLIB ~/rubylib -#----------------------------- -$LOAD_PATH.unshift "/projects/spectre/lib"; - - -# @@PLEAC@@_12.8 -# equivalents in ruby are mkmf, SWIG, or Ruby/DL depending on usage - - -# @@PLEAC@@_12.9 -# no equivalent in ruby - - -# @@PLEAC@@_12.10 -# no equivalent in ruby - - -# @@PLEAC@@_12.11 -module FineTime - def self.time - # to be defined later - end -end - - -module FineTime - def self.time - "its a fine time" - end -end - -puts FineTime.time #=> "its a fine time" - - -# @@PLEAC@@_12.12 -def even_only(n) - raise "#{n} is not even" if (n & 1) != 0 # one way to test - # ... -end -def even_only(n) - $stderr.puts "#{n} is not even" if (n & 1) != 0 - # ... -end - - -# @@PLEAC@@_12.17 -# The library archive for ruby is called Ruby Application archive, -# or shorter RAA, and can be found at http://raa.ruby-lang.org. -# A typical library is installed like this: -# % gunzip some-module-4.54.tar.gz -# % tar xf some-module-4.54.tar -# % cd some-module-4.54.tar -# % ruby install.rb config -# % ruby install.rb setup -# get superuser previleges here if needed for next step -# % ruby install.rb install - -# Some modules use a different process, -# you should find details in the documentation -# Here is an example of such a different process -# % ruby extconf.rb -# % make -# % make install - -# If you want the module installed in your own directory: -# For ruby version specific libraries -# % ruby install.rb config --site-ruby=~/lib -# For version independent libraries -# % ruby install.rb config --site-ruby-common=~/lib - -# Information about possible options for config -# % ruby install.rb --help - -# If you have your own complete distribution -# % ruby install.rb --prefix=path=~/ruby-private - - -# @@PLEAC@@_13.0 -# Classes and objects in Ruby are rather straigthforward -class Person - # Class variables (also called static attributes) are prefixed by @@ - @@person_counter=0 - - # object constructor - def initialize(age, name, alive = true) # Default arg like in C++ - @age, @name, @alive = age, name, alive # Object attributes are prefixed by '@' - @@person_counter += 1 - # There is no '++' operator in Ruby. The '++'/'--' operators are in fact - # hidden assignments which affect variables, not objects. You cannot accomplish - # assignment via method. Since everything in Ruby is object, '++' and '--' - # contradict Ruby OO ideology. Instead '-=' and '+=' are used. - end - - attr_accessor :name, :age # This creates setter and getter methods for @name - # and @age. See 13.3 for detailes. - - # methods modifying the receiver object usually have the '!' suffix - def die! - @alive = false - puts "#{@name} has died at the age of #{@age}." - @alive - end - - def kill(anotherPerson) - print @name, ' is killing ', anotherPerson.name, ".\n" - anotherPerson.die! - end - - # methods used as queries - # usually have the '?' suffix - def alive? - @alive && true - end - - def year_of_birth - Time.now.year - @age - end - - # Class method (also called static method) - def Person.number_of_people - @@person_counter - end -end - -# Using the class: -# Create objects of class Person -lecter = Person.new(47, 'Hannibal') -starling = Person.new(29, 'Clarice', true) -pazzi = Person.new(40, 'Rinaldo', true) - -# Calling a class method -print "There are ", Person.number_of_people, " Person objects\n" - -print pazzi.name, ' is ', (pazzi.alive?) ? 'alive' : 'dead', ".\n" -lecter.kill(pazzi) -print pazzi.name, ' is ', (pazzi.alive?) ? 'alive' : 'dead', ".\n" - -print starling.name , ' was born in ', starling.year_of_birth, "\n" - - -# @@PLEAC@@_13.1 -# If you don't need any initialisation in the constructor, -# you don't need to write a constructor. -class MyClass -end - -class MyClass - def initialize - @start = Time.new - @age = 0 - end -end - -class MyClass - def initialize(inithash) - @start = Time.new - @age = 0 - for key, value in inithash - instance_variable_set("@#{key}", value) - end - end -end - -# @@PLEAC@@_13.2 -# Objects are destroyed by the garbage collector. -# The time of destroying is not predictable. -# The ruby garbage collector can handle circular references, -# so there is no need to write destructor for that. - -# There is no direct support for destructor. -# You can call a custom function, or more specific a proc object, when the -# garbage collector is about to destruct the object, but it is unpredictable -# when this occurs. -# Also if such a finalizer object has a reference to the orignal object, -# this may prevent the original object to get garbage collected. -# Because of this problem the finalize method below is -# a class method and not a instance method. -# So if you need to free resources for an object, like -# closing a socket or kill a spawned subprocess, -# you should do it explicitly. - -class MyClass - def initialize - ObjectSpace.define_finalizer(self, - self.class.method(:finalize).to_proc) - end - def MyClass.finalize(id) - puts "Object #{id} dying at #{Time.new}" - end -end - -# test code -3.times { - MyClass.new -} -ObjectSpace.garbage_collect - - -# @@PLEAC@@_13.3 -# You can write getter and setter methods in a natural way: -class Person - def name - @name - end - def name=(name) - @name = name - end -end - -# But there is a better and shorter way -class Person - attr_reader :age - attr_writer :name - # attr_reader and attr_writer are actually methods in class Class - # which set getter and setter methods for you. -end - -# There is also attr_accessor to create both setters and getters -class Person - attr_accessor :age, :name -end - - -# @@PLEAC@@_13.4 -class Person - # Class variables (also called static attributes) are prefixed by @@ - @@person_counter = 0 - - def Person.population - @@person_counter - end - def initialize - @@person_counter += 1 - ObjectSpace.define_finalizer(self, - self.class.method(:finalize).to_proc) - end - def Person.finalize(id) - @@person_counter -= 1 - end -end -people = [] -10.times { - people.push(Person.new) -} -printf("There are %d people alive", Person.population) - - -FixedArray.class_max_bounds = 100 -alpha = FixedArray.new -puts "Bound on alpha is #{alpha.max_bounds}" - -beta = FixedArray.new -beta.max_bounds = 50 # calls the instance method -beta.class.class_max_bounds = 50 # alternative, calls the class method -puts "Bound on alpha is #{alpha.max_bounds}" - -class FixedArray - @@bounds = 7 - - def max_bounds - @@max_bounds - end - # instance method, which sets the class variable - def max_bounds=(value) - @@max_bounds = value - end - # class method. This can only be called on a class, - # but not on the instances - def FixedArray.class_max_bounds=(value) - @@max_bounds = value - end -end - - -# @@PLEAC@@_13.5 -PersonStruct = Struct.new("Person", :name, :age, :peers) -# creates a class "Person::Struct", which is accessiable with the -# constant "PersonStruct" -p = PersonStruct.new -p = Struct::Person.new # alternative using the classname -p.name = "Jason Smythe" -p.age = 13 -p.peers = ["Wilbur", "Ralph", "Fred"] -p[:peers] = ["Wilbur", "Ralph", "Fred"] # alternative access using symbol -p["peers"] = ["Wilbur", "Ralph", "Fred"] # alternative access using name of field -p[2] = ["Wilbur", "Ralph", "Fred"] # alternative access using index of field -puts "At age #{p.age}, #{p.name}'s first friend is #{p.peers[0]}" - -# The fields of a struct have no special type, like other ruby variables -# you can put any objects in. Therefore the discussions how to specify -# the types of the fields do not apply to ruby. - -FamilyStruct = Struct.new("Family", :head, :address, :members) -folks = FamilyStruct.new -folks.head = PersonStruct.new -dad = folks.head -dad.name = "John" -dad.age = 34 - -# supply of own accessor method for the struct for error checking -class PersonStruct - def age=(value) - if !value.kind_of?(Integer) - raise(ArgumentError, "Age #{value} isn't an Integer") - elsif value > 150 - raise(ArgumentError, "Age #{value} is unreasonable") - end - @age = value - end -end - - -# @@PLEAC@@_13.6 -# The ruby Object class defines a dup and a clone method. -# The dup method is recommended for prototype object creation. -# The default implementation makes a shallow copy, -# but each class can override it, for example to make a deep copy. - -# If you want to call 'new' directly on the instances, -# you can create a instance method "new", which returns a new duplicate. -# This method is distinct from the class method new. -# -class A - def new - dup - end -end - -ob1 = A.new -# later on -ob2 = ob1.new - - -# @@PLEAC@@_13.7 -methname = 'flicker' -obj.send(methname, 10) # calls obj.flicker(10) - -# call three methods on the object, by name -['start', 'run', 'stop'].each do |method_string| - obj.send(method_string) -end - -# Another way is to create a Method object -method_obj = obj.method('flicker') -# And then call it -method_obj.call(10) - - -# @@PLEAC@@_13.8 -# All classes in Ruby inherit from class Object -# and thus all objects share methods defined in this class - -# the class of the object -puts any_object.type - -# Ruby classes are actually objects of class Class and they -# respond to methods defined in Object class as well - -# the superclass of this class -puts any_object.class.superclass - -# ask an object whether it is an instance of particular class -n = 4.7 -puts n.instance_of?(Float) # true -puts n.instance_of?(Numeric) # false - -# ask an object whether it is an instance of class, one of the -# superclasses of the object, or modules included in it -puts n.kind_of?(Float) # true (the class) -puts n.kind_of?(Numeric) # true (an ancestor class) -puts n.kind_of?(Comparable) # true (a mixin module) -puts n.kind_of?(String) # false - -# ask an object whether it can respond to a particular method -puts n.respond_to?('+') # true -puts n.respond_to?('length') # false - -# all methods an object can respond to -'just a string'.methods.each { |m| puts m } - - -# @@PLEAC@@_13.9 -# Actually any class in Ruby is inheritable -class Person - attr_accessor :age, :name - def initialize - @name - @age - end -end -#----------------------------- -dude = Person.new -dude.name = 'Jason' -dude.age = 23 -printf "%s is age %d.\n", dude.name, dude.age -#----------------------------- -# Inheriting from Person -class Employee < Person - attr_accessor :salary -end -#----------------------------- -empl = Employee.new -empl.name = 'Jason' -empl.age = 23 -empl.salary = 200 -printf "%s is age %d, the salary is %d.\n", empl.name, empl.age, empl.salary -#----------------------------- -# Any built-in class can be inherited the same way -class WeirdString < String - def initialize(obj) - super obj - end - def +(anotherObj) # + method in this class is overridden - # to return the sum of string lengths - self.length + anotherObj.length # 'self' can be omitted - end -end -#----------------------------- -a = WeirdString.new('hello') -b = WeirdString.new('bye') - -puts a + b # the overridden + -#=> 8 -puts a.length # method from the superclass, String -#=> 5 - - -# @@PLEAC@@_13.11 -# In ruby you can override the method_missing method -# to have a solution similar to perls AUTOLOAD. -class Person - - def initialize - @ok_fields = %w(name age peers parent) - end - - def valid_attribute?(name) - @ok_fields.include?(name) - end - - def method_missing(namesymbol, *params) - name = namesymbol.to_s - return if name =~ /^A-Z/ - if name.to_s[-1] == ('='[0]) # we have a setter - isSetter = true - name.sub!(/=$/, '') - end - if valid_attribute?(name) - if isSetter - instance_variable_set("@#{name}", *params) - else - instance_variable_get("@#{name}", *params) - end - else - # if no annestor is responsible, - # the Object class will throw a NoMethodError exception - super(namesymbol, *params) - end - end - - def new - kid = Person.new - kid.parent = self - kid - end - -end - -dad = Person.new -dad.name = "Jason" -dad.age = 23 -kid = dad.new -kid.name = "Rachel" -kid.age = 2 -puts "Kid's parent is #{kid.parent.name}" -puts dad -puts kid - -class Employee < Person - def initialize - super - @ok_fields.push("salary", "boss") - end - def ok_fields - @ok_fields - end -end - - -# @@PLEAC@@_13.13 -# The ruby garbage collector pretends to cope with circular structures. -# You can test it with this code: -class RingNode - attr_accessor :next - attr_accessor :prev - attr_reader :name - - def initialize(aName) - @name = aName - ObjectSpace.define_finalizer(self, - self.class.method(:finalize).to_proc) - end - - def RingNode.finalize(id) - puts "Node #{id} dying" - end - - def RingNode.show_all_objects - ObjectSpace.each_object {|id| - puts id.name if id.class == RingNode - } - end -end - -def create_test - a = RingNode.new("Node A") - b = RingNode.new("Node B") - c = RingNode.new("Node C") - a.next = b - b.next = c - c.next = a - a.prev = c - c.prev = b - b.prev = a - - a = nil - b = nil - c = nil -end - -create_test -RingNode.show_all_objects -ObjectSpace.garbage_collect -puts "After garbage collection" -RingNode.show_all_objects - - -# @@PLEAC@@_13.14 -class String - def <=>(other) - self.casecmp other - end -end - -# There is no way to directly overload the '""' (stringify) -# operator in Ruby. However, by convention, classes which -# can reasonably be converted to a String will define a -# 'to_s' method as in the TimeNumber class defined below. -# The 'puts' method will automatcally call an object's -# 'to_s' method as is demonstrated below. -# Furthermore, if a class defines a to_str method, an object of that -# class can be used most any place where the interpreter is looking -# for a String value. - -#--------------------------------------- -# NOTE: Ruby has a builtin Time class which would usually be used -# to manipulate time objects, the following is supplied for -# educational purposes to demonstrate operator overloading. -# -class TimeNumber - attr_accessor :hours,:minutes,:seconds - def initialize( hours, minutes, seconds) - @hours = hours - @minutes = minutes - @seconds = seconds - end - - def to_s - return sprintf( "%d:%02d:%02d", @hours, @minutes, @seconds) - end - - def to_str - to_s - end - - def +( other) - seconds = @seconds + other.seconds - minutes = @minutes + other.minutes - hours = @hours + other.hours - if seconds >= 60 - seconds %= 60 - minutes += 1 - end - if minutes >= 60 - minutes %= 60 - hours += 1 - end - return TimeNumber.new(hours, minutes, seconds) - end - - def -(other) - raise NotImplementedError - end - - def *(other) - raise NotImplementedError - end - - def /( other) - raise NotImplementedError - end -end - -t1 = TimeNumber.new(0, 58, 59) -sec = TimeNumber.new(0, 0, 1) -min = TimeNumber.new(0, 1, 0) -puts t1 + sec + min + min - -#----------------------------- -# StrNum class example: Ruby's builtin String class already has the -# capabilities outlined in StrNum Perl example, however the '*' operator -# on Ruby's String class acts differently: It creates a string which -# is the original string repeated N times. -# -# Using Ruby's String class as is in this example: -x = "Red"; y = "Black" -z = x+y -r = z*3 # r is "RedBlackRedBlackRedBlack" -puts "values are #{x}, #{y}, #{z}, and #{r}" -print "#{x} is ", x < y ? "LT" : "GE", " #{y}\n" -# prints: -# values are Red, Black, RedBlack, and RedBlackRedBlackRedBlack -# Red is GE Black - -#----------------------------- -class FixNum - REGEX = /(\.\d*)/ - DEFAULT_PLACES = 0 - attr_accessor :value, :places - def initialize(value, places = nil) - @value = value - if places - @places = places - else - m = REGEX.match(value.to_s) - if m - @places = m[0].length - 1 - else - @places = DEFAULT_PLACES - end - end - end - - def +(other) - FixNum.new(@value + other.value, max(@places, other.places)) - end - - def *(other) - FixNum.new(@value * other.value, max(@places, other.places)) - end - - def /(other) - puts "Divide: #{@value.to_f/other.value.to_f}" - result = FixNum.new(@value.to_f/other.value.to_f) - result.places = max(result.places,other.places) - result - end - - def to_s - sprintf("STR%s: %.*f", self.class.to_s , @places, @value) #. - end - - def to_str - to_s - end - - def to_i #convert to int - @value.to_i - end - - def to_f #convert to float` - @value.to_f - end - - private - def max(a,b) - a > b ? a : b - end -end - -def demo() - x = FixNum.new(40) - y = FixNum.new(12, 0) - - puts "sum of #{x} and #{y} is #{x+y}" - puts "product of #{x} and #{y} is #{x*y}" - - z = x/y - puts "#{z} has #{z.places} places" - unless z.places - z.places = 2 - end - - puts "div of #{x} by #{y} is #{z}" - puts "square of that is #{z*z}" -end - -if __FILE__ == $0 - demo() -end - - -# @@PLEAC@@_14.1 -# There are dbm, sdbm, gdbm modules -# and the bdb module for accessing the berkeley db -# sdbm seem to be available on the most systems, -# so we use it here -# -require "sdbm" -SDBM.open("filename", 0666) { |dbobj| - # raises exception if open error - - # the returned sdbm-dbobj has most of the methods of a hash - v = dbobj["key"] - dbobj["key"] = "newvalue" - if dbobj.has_key?("key") - # ... - end - dbobj.delete("key2") -} -# database is open only inside the block. - -# It is also possible to use a open .. close pair: -dbobj = SDBM.open("filename", 0666) -#.. do something with dbobj -dbobj.close - -#!/usr/bin/ruby -w -# userstats - generate statistics on who is logged in -# call with usernames as argument to display the totals -# for the given usernames, call with "ALL" to display all users - -require "sdbm" -filename = '/tmp/userstats.db' -SDBM.open(filename, 0666) { |dbobj| - if ARGV.length > 0 - if ARGV[0] == "ALL" - # ARGV is constant, so we need the variable userlist - userlist = dbobj.keys().sort() - else - userlist = ARGV - end - userlist.each { |user| - print "#{user}\t#{dbobj[user]}\n" - } - else - who = `who` - who.split("\n").each { |line| - md = /^(\S+)/.match(line) - raise "Bad line from who: #{line}" unless md - # sdbm stores only strings, so "+=" doesn't work, - # we need to convert them expicitly back to integer. - if dbobj.has_key?(md[0]) - dbobj[md[0]] = dbobj[md[0]].to_i + 1 - else - dbobj[md[0]] = "1" - end - } - end -} - - -# @@PLEAC@@_14.2 -# using open and clear -dbobj = SDBM.open("filename", 0666) -dbobj.clear() -dbobj.close() -# deleting file and recreating it -# the filenames depend on the flavor of dbm you use, -# for example sdbm has two files named filename.pag and filename.dir, -# so you need to delete both files -begin - File.delete("filename") - # raises Exception if not exist - dbobj = SDBM.open("filename", 0666) -rescue - # add error handling here -end - - -# @@PLEAC@@_14.3 -# sdbm2gdbm: converts sdbm database to a gdbm database -require "sdbm" -require "gdbm" - -unless ARGV.length == 2 - fail "usage: sdbm2gdbm infile outfile" -end -infile = ARGV[0] -outfile = ARGV[1] - -sdb = SDBM.open(infile) -gdb = GDBM.open(outfile, 0666) -sdb.each { |key, val| - gdb[key] = val -} -gdb.close -sdb.close - - -# @@PLEAC@@_14.4 -#!/usr/bin/ruby -w -# dbmmerge: merges two dbm databases -require "sdbm" - -unless ARGV.length == 3 - fail "usage: dbmmerge indb1 indb2 outdb" -end -infile1 = ARGV[0] -infile2 = ARGV[0] -outfile = ARGV[2] - -in1 = SDBM.open(infile1, nil) -in2 = SDBM.open(infile2, nil) -outdb = SDBM.open(outfile, 0666) - -[in1, in2].each { |indb| - indb.each { |key, val| - if outdb.has_key?(key) - # decide which value to set. - # set outdb[key] if necessary - else - outdb[key] = val - end - } -} -in1.close -in2.close -outdb.close - - -# @@PLEAC@@_14.7 -# we write a tie method that extends the Array class. -# It reads the file into the memory, executes the code block -# in which you can manipulate the array as needed, and writes -# the array back to the file after the end of the block execution -class Array - def tie(filename, flags) - File.open(filename, flags) { |f| - f.each_line { |line| - self.push(line.chomp) - } - yield - f.rewind - each { |line| - if line - f.puts(line) - else - f.puts "" - end - } - } - end -end - -array = Array.new -array.tie("/tmp/textfile.txt", File::RDWR|File::CREAT) { - array[4] = "a new line 4" -} - -# The tied array can be manipulated like a normal array, -# so there is no need for a special API, and the recno_demo program -# to demonstrate is API is useless - - -# tied array demo: show how to use array with a tied file -filename = "db_file.txt" -lines = Array.new -File.unlink(filename) if File.exists?(filename) -lines.tie(filename, File::RDWR | File::CREAT) { - # first create a textfile to play with - lines[0] = "zero" - lines[1] = "one" - lines[2] = "two" - lines[3] = "three" - lines[4] = "four" - - # print the records in order. - # Opposed to perl, the tied array behaves exactly as a normal array - puts "\nOriginal" - for i in 0..(lines.length-1) - puts "#{i}: #{lines[i]}" - end - - #use push and pop - a = lines.pop - lines.push("last") - puts("The last line was [#{a}]") - - #use shift and unshift - a = lines.shift - lines.unshift("first") - puts("The first line was [#{a}]") - - # add record after record 2 - i = 2 - lines.insert(i + 1, "Newbie") - - # add record before record one - i = 1 - lines.insert(i, "New One") - - # delete record 3 - lines.delete_at(3) - - #now print the records in reverse order - puts "\nReverse" - (lines.length - 1).downto(0){ |i| - puts "#{i}: #{lines[i]}" - } - -} - - -# @@PLEAC@@_14.8 -# example to store complex data in a database -# uses marshall from the standard library -require "sdbm" -db = SDBM.open("pleac14-8-database", 0666) - -# convert the Objects into strings and back by using the Marshal module. -# Most normal objects can be converted out of the box, -# but not special things like procedure objects, -# IO instance variables, singleton objects - -db["Tom Christiansen"] = Marshal.dump(["book author", "tchrist@perl.com"]) -db["Tom Boutell"] = Marshal.dump(["shareware author", -"boutell@boutell.com"]) - -name1 = "Tom Christiansen" -name2 = "Tom Boutell" - -tom1 = Marshal.load(db[name1]) -tom2 = Marshal.load(db[name2]) - -puts "Two Toming: #{tom1} #{tom2}" - -if tom1[0] == tom2[0] && tom1[1] == tom2[1] - puts "You're having runtime fun with one Tom made two." -else - puts "No two Toms are ever alike" -end - -# To change parts of an entry, get the whole entry, change the parts, -# and save the whole entry back -entry = Marshal.load(db["Tom Boutell"]) -entry[0] = "Poet Programmer" -db["Tom Boutell"] = Marshal.dump(entry) -db.close - - -# @@PLEAC@@_14.9 -# example to make data persistent -# uses Marshal from the standard lib -# Stores the data in a simple file, -# see 14.8 on how to store it in a dbm file - -# The BEGIN block is executed before the rest of the script -# we use global variables here because local variables -# will go out of scope and are not accessible from the main script - -BEGIN { - $persistent_store = "persitence.dat" - begin - File.open($persistent_store) do |f| - $stringvariable1 = Marshal.load(f) - $arrayvariable2 = Marshal.load(f) - end - rescue - puts "Can not open #{$persistent_store}" - # Initialisation if this script runs the first time - $stringvariable1 = "" - $arrayvariable2 = [] - end -} - -END { - File.open($persistent_store, "w+") do |f| - Marshal.dump($stringvariable1, f) - Marshal.dump($arrayvariable2, f) - end -} - -# simple test program -puts $stringvariable1 -puts $arrayvariable2 -$stringvariable1 = "Hello World" -$arrayvariable2.push(5) -puts $stringvariable1 -puts $arrayvariable2 - - -# @@PLEAC@@_14.10 -#!/usr/bin/ruby -w -# Ruby has a dbi module with an architecture similar -# to the Perl dbi module: the dbi module provides an unified -# interface and uses specialized drivers for each dbms vendor -# -begin - DBI.connect("DBI:driver:driverspecific", "username", "auth") { - |dbh| - - dbh.do(SQL1) - - dbh.prepare(SQL2){ |sth| - sth.execute - sth.fetch {|row| - # ... - } - } # end of block finishes the statement handle - } # end of block closes the database connection -rescue DBI::DatabaseError => e - puts "dbi error occurred" - puts "Error code: #{e.err}" - puts "Error message: #{e.errstr}" -end - -#!/usr/bin/ruby -w -# dbusers - example for mysql which creates a table, -# fills it with values, retrieves the values back, -# and finally destroys the table. - -require "dbi" - -# replacement for the User::pwnt module -def getpwent - result = [] - File.open("/etc/passwd") {|file| - file.each_line {|line| - next if line.match(/^#/) - cols = line.split(":") - result.push([cols[2], cols[0]]) - } - } - result -end - -begin - DBI.connect("DBI:Mysql:pleacdatabase", "pleac", "pleacpassword") { - |conn| - - conn.do("CREATE TABLE users (uid INT, login CHAR(8))") - - users = getpwent - - conn.prepare("INSERT INTO users VALUES (?,?)") {|sth| - users.each {|entry| - sth.execute(entry[0], entry[1]) - } - } - - conn.execute("SELECT uid, login FROM users WHERE uid < 50") {|sth| - sth.fetch {|row| - puts row.collect {|col| - if col.nil? - "(null)" - else - col - end - }.join(", ") - } - } - - conn.do("DROP TABLE users") - } -rescue DBI::DatabaseError => e - puts "dbi error occurred" - puts "Error code: #{e.err}" - puts "Error message: #{e.errstr}" -end - - -# @@PLEAC@@_15.1 -# This test program demonstrates parsing program arguments. -# It uses the optparse library, which is included with ruby 1.8 -# It handles classic unix style and gnu style options -require 'optparse' - -@debugmode = false -@verbose = false - -ARGV.options do |opts| - opts.banner = "Usage: ruby #{$0} [OPTIONS] INPUTFILES" - - opts.on("-h", "--help", "show this message") { - puts opts - exit - } - # The OptionParser#on method is called with a specification of short - # options, of long options, a data type spezification and user help - # messages for this option. - # The method analyses the given parameter and decides what it is, - # so you can leave out the long option if you don't need it - opts.on("-v", "--[no-]verbose=[FLAG]", TrueClass, "run verbosly") { - |@verbose| # sets @verbose to true or false - } - opts.on("-D", "--DEBUG", TrueClass, "turns on debug mode" ){ - |@debugmode| # sets @debugmode to true - } - opts.on("-c", "--count=NUMBER", Integer, "how many times we do it" ){ - |@count| # sets @count to given integer - } - opts.on("-o", "--output=FILE", String, "file to write output to"){ - |@outputfile| # sets @outputfile to given string - } - opts.parse! -end - -# example to use the options in the main program -puts "Verbose is on" if @verbose -puts "Debugmode is on" if @debugmode -puts "Outfile is #{@outputfile}" if defined? @outputfile -puts "Count is #{@count}" if defined? @count -ARGV.each { |param| - puts "Got parameter #{param}" -} - - -# @@PLEAC@@_15.4 -buf = "\0" * 8 -$stdout.ioctl(0x5413, buf) -ws_row, ws_col, ws_xpixel, ws_ypixel = buf.unpack("S4") - -raise "You must have at least 20 characters" unless ws_col >= 20 -max = 0 -values = (1..5).collect { rand(20) } # generate an array[5] of rand values -for i in values - max = i if max < i -end -ratio = Float(ws_col-12)/max # chars per unit -for i in values - printf "%8.1f %s\n", i, "*" * (ratio*i) -end - -# gives, for example: -# 15.0 ******************************* -# 10.0 ********************* -# 5.0 ********** -# 14.0 ***************************** -# 18.0 ************************************** - - -# @@PLEAC@@_16.1 -output = `program args` # collect output into one multiline string -output = `program args`.split # collect output into array, one line per -element - -readme = IO.popen("ls") -output = "" -while readme.gets do - output += $_ -end -readme.close - -`fsck -y /dev/rsd1a` # BAD AND SCARY in Perl because it's managed by the shell - # I donna in Ruby ... - -# so the "clean and secure" version -readme, writeme = IO.pipe -pid = fork { - # child - $stdout = writeme - readme.close - exec('find', '..') -} -# parent -Process.waitpid(pid, 0) -writeme.close -while readme.gets do - # do something with $_ -end - - -# @@PLEAC@@_16.2 -status = system("xemacs #{myfile}") - -status = system("xemacs", myfile) - -system("cmd1 args | cmd2 | cmd3 >outfile") -system("cmd args <infile >outfile 2>errfile") - -# stop if the command fails -raise "$program exited funny: #{$?}" unless system("cmd", "args1", "args2") - -# get the value of the signal sent to the child -# even if it is a SIGINT or SIGQUIT -system(arglist) -raise "program killed by signal #{$?}" if ($? & 127) != 0 - -pid = fork { - trap("SIGINT", "IGNORE") - exec("sleep", "10") -} -trap ("SIGINT") { - puts "Tsk tsk, no process interruptus" -} -Process.waitpid(pid, 0) - -# Ruby doesn't permit to lie to the program called by a 'system'. -# (ie specify what return argv[0] in C, $0 in Perl/Ruby ...) -# A (dirty) way is to create a link (under Unix), run this link and -# erase it. Somebody has a best idea ? - - -# @@PLEAC@@_16.3 -exec("archive *.data") - -exec("archive", "accounting.data") - -exec("archive accounting.data") - - -# @@PLEAC@@_16.4 -# read the output of a program -IO.popen("ls") {|readme| - while readme.gets do - # ... - end -} -# or -readme = IO.popen("ls") -while readme.gets do - # ... -end -readme.close - -# "write" in a program -IO.popen("cmd args","w") {|pipe| - pipe.puts("data") - pipe.puts("foo") -} - -# close wait for the end of the process -read = IO.popen("sleep 10000") # child goes to sleep -read.close # and the parent goes to lala land - -writeme = IO.popen("cmd args", "w") -writeme.puts "hello" # program will get hello\n on STDIN -writeme.close # program will get EOF on STDIN - -# send in a pager (eg less) all output -$stdout = IO.popen("/usr/bin/less","w") -print "huge string\n" * 10000 - - -# @@PLEAC@@_16.5 -#----------------------------- -def head(lines = 20) - pid = open("|-","w") - if pid == nil - return - else - while gets() do - pid.print - lines -= 1 - break if lines == 0 - end - end - exit -end - -head(100) -while gets() do - print -end -#----------------------------- -1: > Welcome to Linux, version 2.0.33 on a i686 - -2: > - -3: > "The software required `Windows 95 or better', - -4: > so I installed Linux." -#----------------------------- -> 1: Welcome to Linux, Kernel version 2.0.33 on a i686 - -> 2: - -> 3: "The software required `Windows 95 or better', - -> 4: so I installed Linux." -#----------------------------- -#!/usr/bin/ruby -# qnumcat - demo additive output filters - -def number() - pid = open("|-","w") - if pid == nil - return - else - while gets() do pid.printf("%d: %s", $., $_); end - end - exit -end - -def quote() - pid = open("|-","w") - if pid == nil - return - else - while gets() do pid.print "> #{$_}" end - end - exit -end - -number() -quote() - -while gets() do - print -end -$stdout.close -exit - - -# @@PLEAC@@_16.6 -ARGV.map! { |arg| - arg =~ /\.(gz|Z)$/ ? "|gzip -dc #{arg}" : arg -} -for file in ARGV - fh = open(file) - while fh.gets() do - # ....... - end -end -#----------------------------- -ARGV.map! { |arg| - arg =~ %r#^\w+://# ? "|GET #{arg}" : arg # -} -for file in ARGV - fh = open(file) - while fh.gets() do - # ....... - end -end -#----------------------------- -pwdinfo = (`domainname` =~ /^(\(none\))?$/) ? '/etc/passwd' : '|ypcat passwd'; -pwd = open(pwdinfo); -#----------------------------- -puts "File, please? "; -file = gets().chomp(); -fh = open(file); - - -# @@PLEAC@@_16.7 -output = `cmd 2>&1` # with backticks -# or -ph = open("|cmd 2>&1") # with an open pipe -while ph.gets() { } # plus a read -#----------------------------- -output = `cmd 2>/dev/null` # with backticks -# or -ph = open("|cmd 2>/dev/null") # with an open pipe -while ph.gets() { } # plus a read -#----------------------------- -output = `cmd 2>&1 1>/dev/null` # with backticks -# or -ph = open("|cmd 2>&1 1>/dev/null") # with an open pipe -while ph.gets() { } # plus a read -#----------------------------- -output = `cmd 3>&1 1>&2 2>&3 3>&-` # with backticks -# or -ph = open("|cmd 3>&1 1>&2 2>&3 3>&-") # with an open pipe -while ph.gets() { } # plus a read -#----------------------------- -system("program args 1>/tmp/program.stdout 2>/tmp/program.stderr") -#----------------------------- -output = `cmd 3>&1 1>&2 2>&3 3>&-` -#----------------------------- -fd3 = fd1 -fd1 = fd2 -fd2 = fd3 -fd3 = undef -#----------------------------- -system("prog args 1>tmpfile 2>&1") -system("prog args 2>&1 1>tmpfile") -#----------------------------- -# system ("prog args 1>tmpfile 2>&1") -fd1 = "tmpfile" # change stdout destination first -fd2 = fd1 # now point stderr there, too -#----------------------------- -# system("prog args 2>&1 1>tmpfile") -fd2 = fd1 # stderr same destination as stdout -fd1 = "tmpfile" # but change stdout destination -#----------------------------- -# It is often better not to rely on the shell, -# because of portability, possible security problems -# and bigger resource usage. So, it is often better to use the open3 library. -# See below for an example. -# opening stdin, stdout, stderr -require "open3" -stdin, stdout, stderr = Open3.popen('cmd') - - -# @@PLEAC@@_16.8 -#----------------------------- -# Contrary to perl, we don't need to use a module in Ruby -fh = Kernel.open("|" + program, "w+") -fh.puts "here's your input\n" -output = fh.gets() -fh.close() -#----------------------------- -Kernel.open("|program"),"w+") # RIGHT ! -#----------------------------- -# Ruby has already object methods for I/O handles -#----------------------------- -begin - fh = Kernel.open("|" + program_and_options, "w+") -rescue - if ($@ ~= /^open/) - $stderr.puts "open failed : #{$!} \n #{$@} \n" - break - end - raise # reraise unforseen exception -end - - -# @@PLEAC@@_16.13 -#% kill -l -#HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE -#ALRM TERM CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM -#PROF WINCH POLL PWR -#----------------------------- -#% ruby -e 'puts Signal.list.keys.join(" ")' -#PWR USR1 BUS USR2 TERM SEGV KILL POLL STOP SYS TRAP IOT HUP INT # -#WINCH XCPU TTIN CLD TSTP FPE IO TTOU PROF CHLD CONT PIPE ABRT -#VTALRM QUIT ILL XFSZ URG ALRM -#----------------------------- -# After that, the perl script create an hash equivalent to Signal.list, -# and an array. The array can be obtained by : -signame = [] -Signal.list.each { |name, i| signame[i] = name } - - -# @@PLEAC@@_16.14 -Process.kill(9, pid) # send $pid a signal 9 -Process.kill(-1, Process.getpgrp()) # send whole job a signal 1 -Process.kill("USR1", $$) # send myself a SIGUSR1 -Process.kill("HUP", pid1, pid2, pid3) # send a SIGHUP to processes in @pids -#----------------------------- -begin - Process.kill(0, minion) - puts "#{minion} is alive!" -rescue Errno::EPERM # changed uid - puts "#{minion} has escaped my control!"; -rescue Errno::ESRCH - puts "#{minion} is deceased."; # or zombied -rescue - puts "Odd; I couldn't check the status of #{minion} : #{$!}" -end - - -# @@PLEAC@@_16.15 -Kernel.trap("QUIT", got_sig_quit) # got_sig_quit = Proc.new { puts "Quit\n" } -trap("PIPE", "got_sig_quit") # def got_sig_pipe ... -trap("INT") { ouch++ } # increment ouch for every SIGINT -#----------------------------- -trap("INT", "IGNORE") # ignore the signal INT -#----------------------------- -trap("STOP", "DEFAULT") # restore default STOP signal handling - - -# @@PLEAC@@_16.16 -# the signal handler -def ding - trap("INT", "ding") - puts "\aEnter your name!" -end - -# prompt for name, overriding SIGINT -def get_name - save = trap("INT", "ding") - - puts "Kindly Stranger, please enter your name: " - name = gets().chomp() - trap("INT", save) - name -end - - -# @@PLEAC@@_16.21 -# implemented thanks to http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/1760 -require 'timeout' - -# we'll do something vastly more useful than cookbook to demonstrate timeouts -begin - timeout(5) { - waitsec = rand(10) - puts "Let's see if a sleep of #{waitsec} seconds is longer than 5 seconds..." - system("sleep #{waitsec}") - } - puts "Timeout didn't occur" -rescue Timeout::Error - puts "Timed out!" -end - - -# @@PLEAC@@_17.1 -# A basic TCP client connection -require 'socket' -begin - t = TCPSocket.new('www.ruby-lang.org', 'www') -rescue - puts "error: #{$!}" -else - # ... do something with the socket - t.print "GET / HTTP/1.0\n\n" - answer = t.gets(nil) - # and terminate the connection when we're done - t.close -end - -# Using the evil low level socket API -require 'socket' -# create a socket -s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) -# build the address of the remote machine -sockaddr_server = [Socket::AF_INET, 80, - Socket.gethostbyname('www.ruby-lang.org')[3], - 0, 0].pack("snA4NN") -# connect -begin - s.connect(sockaddr_server) -rescue - puts "error: #{$!}" -else - # ... do something with the socket - s.print "GET / HTTP/1.0\n\n" - # and terminate the connection when we're done - s.close -end - -# TCP connection with management of error (DNS) -require 'socket' -begin - client = TCPSocket.new('does not exists', 'www') -rescue - puts "error: #{$!}" -end - -# TCP connection with a time out -require 'socket' -require 'timeout' -begin - timeout(1) do #the server has one second to answer - client = TCPSocket.new('www.host.com', 'www') - end -rescue - puts "error: #{$!}" -end - - -# @@PLEAC@@_17.12 -require 'socket' - -class Preforker - attr_reader (:child_count) - - def initialize(prefork, max_clients_per_child, port, client_handler) - @prefork = prefork - @max_clients_per_child = max_clients_per_child - @port = port - @child_count = 0 - - @reaper = proc { - trap('CHLD', @reaper) - pid = Process.wait - @child_count -= 1 - } - - @huntsman = proc { - trap('CHLD', 'IGNORE') - trap('INT', 'IGNORE') - Process.kill('INT', 0) - exit - } - - @client_handler=client_handler - end - - def child_handler - trap('INT', 'EXIT') - @client_handler.setUp - # wish: sigprocmask UNblock SIGINT - @max_clients_per_child.times { - client = @server.accept or break - @client_handler.handle_request(client) - client.close - } - @client_handler.tearDown - end - - def make_new_child - # wish: sigprocmask block SIGINT - @child_count += 1 - pid = fork do - child_handler - end - # wish: sigprocmask UNblock SIGINT - end - - def run - @server = TCPserver.open(@port) - trap('CHLD', @reaper) - trap('INT', @huntsman) - loop { - (@prefork - @child_count).times { |i| - make_new_child - } - sleep .1 - } - end -end - -#----------------------------- -#!/usr/bin/ruby - -require 'Preforker' - -class ClientHandler - def setUp - end - - def tearDown - end - - def handle_request(client) - # do stuff - end -end - -server = Preforker.new(1, 100, 3102, ClientHandler.new) -server.run - - -# @@PLEAC@@_18.2 -require 'net/ftp' - -begin - ftp = Net::FTP::new("ftp.host.com") - ftp.login(username,password) - ftp.chdir(directory) - ftp.get(filename) - ftp.put(filename) -rescue Net::FTPError - $stderr.print "FTP failed: " + $! -ensure - ftp.close() if ftp -end - -# A better solution for a local use could be : -Net::FTP::new("ftp.host.com") do |ftp| - ftp.login(username,password) - ftp.chdir(directory) - ftp.get(filename) - ftp.put(filename) -end - -# If you have only one file to get, there is a simple solution : -require 'open-uri' -open("ftp://www.ruby-lang.org/path/filename") do |fh| - # read from filehandle fh -end -#-------------------------------------------- -# to wait a defined time for the connection, -# use the timeout module -require 'timeout' -begin - timeout(30){ - ftp = Net::FTP::new("ftp.host.com") - ftp.debug_mode = true - } -rescue Net::FTPError - $stderr.puts "Couldn't connect." -rescue Timeout::Error - $stderr.puts "Timeout while connecting to server." -end - -begin - ftp.login() -rescue Net::FTPError - $stderr.print "Couldn't authentificate.\n" -end - -begin - ftp.login(username) -rescue Net::FTPError - $stderr.print "Still couldn't authenticate.\n" -end - -begin - ftp.login(username, password) -rescue Net::FTPError - $stderr.print "Couldn't authenticate, even with explicit - username and password.\n" -end - -begin - ftp.login(username, password, account) -rescue Net::FTPError - $stderr.print "No dice. It hates me.\n" -end -#----------------------------- -ftp.put(localfile, remotefile) -#----------------------------- -# Sending data from STDIN is not directly supported -# by the ftp library module. A possible way to do it is to use the -# storlines method directly to send raw commands to the ftp server. -#----------------------------- -ftp.get(remotefile, localfile) -#----------------------------- -ftp.get(remotefile) { |data| puts data } -#----------------------------- -ftp.chdir("/pub/ruby") -print "I'm in the directory ", ftp.pwd(), "\n" -#----------------------------- -ftp.mkdir("/pub/ruby/new_dir") -#----------------------------- -lines = ftp.ls("/pub/ruby/") -# => ["drwxr-xr-x 2 matz users 4096 July 17 1998 1.0", ... ] - -latest = ftp.dir("/pub/ruby/*.tgz").sort.last - -ftp.nlst("/pub/ruby") -# => ["/pub/ruby/1.0", ... ] -#----------------------------- -ftp.quit() - - -# @@PLEAC@@_18.6 -require 'net/telnet' -t = Net::Telnet::new( "Timeout" => 10, - "Prompt" => /%/, - "Host" => host ) -t.login(username, password) -files = t.cmd("ls") -t.print("top") -process_string = t.waitfor(/\d+ processes/) -t.close -#----------------------------- -/[$%#>] \z/n -#----------------------------- -# In case of an error, the telnet module throws an exception. -# For control of the behavior in case of an error, -# you just need to catch the exceptions and do your custom -# error handling. -#----------------------------- -begin - telnet.login(username, password) -rescue TimeoutError - fail "Login failed !\n" -end -#----------------------------- -telnet.waitfor('/--more--/') -#----------------------------- -telnet.waitfor(String => 'greasy smoke', Timeout => 30) - - -# @@PLEAC@@_18.7 -require 'ping' - -puts "#{host} is alive.\n" if Ping.pingecho(host); -#----------------------------- -# the ping module only use TCP ping, not ICMP even if we are root -if Ping.pingecho("kingkong.com") - puts "The giant ape lives!\n"; -else - puts "All hail mighty Gamera, friend of children!\n"; -end - - -# @@PLEAC@@_19.1 -#!/usr/local/bin/ruby -w -# hiweb - load CGI class to decode information given by web server - -require 'cgi' - -cgi = CGI.new('html3') - -# get a parameter from a form -value = cgi.params['PARAM_NAME'][0] - -# output a document -cgi.out { - cgi.html { - cgi.head { cgi.title { "Howdy there!" } } + - cgi.body { cgi.p { "You typed: " + cgi.tt { - CGI.escapeHTML(value) } } } - } -} - -require 'cgi' -cgi = CGI.new -who = cgi.param["Name"][0] # first param in list -phone = cgi.param["Number"][0] -picks = cgi.param["Choices"] # complete list - -print cgi.header( 'type' => 'text/plain', - 'expires' => Time.now + (3 * 24 * 60 * 60) ) - - -# @@PLEAC@@_19.3 -#!/usr/local/bin/ruby -w -# webwhoami - show web user's id -require 'etc' -print "Content-Type: text/plain\n\n" -print "Running as " + Etc.getpwuid.name + "\n" - -# % ruby -wc cgi-script # just check syntax - -# % ruby -w cgi-script # params from stdin -# (offline mode: enter name=value pairs on standard input) -# name=joe -# number=10 -# ^D - -# % ruby -w cgi-script name=joe number=10 # run with mock form input -# % ruby -d cgi-script name=joe number=10 # ditto, under the debugger - -# POST method script in csh -# % (setenv HTTP_METHOD POST; ruby -w cgi-script name=joe number=10) -# POST method script in sh -# % HTTP_METHOD=POST perl -w cgi-script name=joe number=10 - - -# @@PLEAC@@_19.4 -# ruby has several security levels, the level "1" is similar to perls taint mode. -# It can be switched on by providing the -T command line parameter -# or by setting $SAFE to 1. Setting $SAFE to 2,3 or 4 restricts possible -# harmful operations further. - -#!/usr/bin/ruby -T -$SAFE = 1 -File.open(ARGV[0], "w") -# ruby warns with: -# taint1.rb:2:in `initialize': Insecure operation - initialize (SecurityError) - -$SAFE = 1 -file = ARGV[0] -unless /^([\w.-]+)$/.match(file) - raise "filename #{file} has invalid characters" -end -file = $1 -# In ruby, even the back reference from a regular expression stays tainted. -# you need to explicitly untaint the variable: -file.untaint -File.open(file, "w") - -# Race condition exists like in perl: -unless File.exists(filename) # Wrong because of race condition - File.open(filename, "w") -end - - - -# @@PLEAC@@_19.10 -preference_value = cgi.cookies["preference name"][0] - -packed_cookie = CGI::Cookie.new("name" => "preference name", - "value" => "whatever you'd like", - "expires" => Time.local(Time.now.year + 2, - Time.now.mon, Time.now.day, Time.now.hour, Time.now.min, Time.now.sec) ) - -cgi.header("cookie" => [packed_cookie]) - -#!/usr/local/bin/ruby -w -# ic_cookies - sample CGI script that uses a cookie -require 'cgi' - -cgi = CGI.new('html3') - -cookname = "favorite ice cream" -favorite = cgi.params["flavor"][0] -tasty = cgi.cookies[cookname][0] || 'mint' - -unless favorite - cgi.out { - cgi.html { - cgi.head { cgi.title { "Ice Cookies" } } + - cgi.body { - cgi.h1 { "Hello Ice Cream" } + - cgi.hr + - cgi.form { - cgi.p { "Please select a flavor: " + - cgi.text_field("flavor", tasty ) } - } + - cgi.hr - } - } - } -else - cookie = CGI::Cookie.new( "name" => cookname, - "value" => favorite, - "expires" => Time.local(Time.now.year + 2, -Time.now.mon, Time.now.day, Time.now.hour, Time.now.min, Time.now.sec) ) - cgi.out("cookie" => [cookie]) { - cgi.html { - cgi.head { cgi.title { "Ice Cookies" } } + - cgi.body { - cgi.h1 { "Hello Ice Cream" } + - cgi.p { "You chose as your favorite flavor `#{favorite}'." } - } - } - } -end - - -# @@PLEAC@@_20.9 -def templatefile(filename, fillings) - aFile = File.new(filename, "r") - text = aFile.read() - aFile.close() - pattern = Regexp.new('%%(.*?)%%') - text.gsub!(pattern) { - fillings[$1] || "" - } - text -end - -fields = { - 'username' => whats_his_name, - 'count' => login_count, - 'total' => minutes_used -} -puts templatefile('simple.template', fields) - -# @@INCOMPLETE@@ -# An example using databases is missing - |