summaryrefslogtreecommitdiff
path: root/tests/examplefiles/example.rb
diff options
context:
space:
mode:
authorgbrandl <devnull@localhost>2007-02-14 17:18:40 +0100
committergbrandl <devnull@localhost>2007-02-14 17:18:40 +0100
commit3e1463ced2669526d6c1ea5cc7748438367c2847 (patch)
treeda8e5b61674c372d5e70a082ba4423c3aff9dd66 /tests/examplefiles/example.rb
parent0fa948e73c48996de904aeb2f0e4990fc40385ec (diff)
downloadpygments-3e1463ced2669526d6c1ea5cc7748438367c2847.tar.gz
[svn] Shorten some testfiles, silence some pylint warnings,
add a latex formatter unittest.
Diffstat (limited to 'tests/examplefiles/example.rb')
-rw-r--r--tests/examplefiles/example.rb5704
1 files changed, 0 insertions, 5704 deletions
diff --git a/tests/examplefiles/example.rb b/tests/examplefiles/example.rb
index 8a3304ba..93f8dc2b 100644
--- a/tests/examplefiles/example.rb
+++ b/tests/examplefiles/example.rb
@@ -1850,5707 +1850,3 @@ module BBCode
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 '<span class="error">' if DEBUG
- add_text garbage
- add_html '</span>' 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
- [&plusmn] | &
- ["[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<hr>\n"
- true
- end
-
- when '"'
- if @scanner.scan(QUOTED_SCAN)
- @encoder.add_text unescape(@scanner[1])
- true
- end
-
- when '&'
- if @scanner.scan(ENTITY_SCAN)
- @encoder.add_entity @scanner[1]
- true
- end
-
- when Smileys::SMILEY_START_CHARSET
- @scanner.pos = @scanner.pos - 1 # (ungetch)
- if @scanner.scan(SMILEY_SCAN)
- @encoder.add_html Smileys.smiley_to_image(@scanner.matched)
- true
- end
-
- end # case
-
- return garbage_out(tag_start) unless handled
-
- @scanner.scan(TAG_END_SCAN) unless already_closed
- end
-
- ATTRIBUTES_SCAN = /
- (
- [^\]"\\]*
- (?:
- (?:
- \\.
- |
- "
- [^"\\]*
- (?:
- \\.
- [^"\\]*
- )*
- "?
- )
- [^\]"\\]*
- )*
- )
- \]?
- /x
-
- def handle_classic_tag name, closing
- debug 'TAG: ' + (closing ? '/' : '') + name
- # flatten
- name.downcase!
- tag_class = TAG_LIST[name]
- return unless tag_class
-
- #debug((opening ? 'OPEN ' : 'CLOSE ') + tag_class.name)
-
- # create an attribute object to handle it
- @scanner.scan(ATTRIBUTES_SCAN)
- #debug name + ':' + @scanner[1]
- attr = Attribute.create @scanner[1]
- #debug 'ATTRIBUTES %p ' % attr #unless attr.empty?
-
- #debug 'closing: %p; name=%s, attr=%p' % [closing, name, attr]
-
- # OPEN
- if not closing and tag = @tagstack.try_open_class(tag_class, attr)
- #debug 'opening'
- tag.do_open @scanner
- # this should be done by the tag itself.
- if attr.empty_tag?
- tag.handle_empty
- @tagstack.close_tag
- elsif tag.special_content?
- handle_special_content(tag)
- @tagstack.close_tag
- # # ignore asterisks directly after the opening; these are phpBBCode
- # elsif tag.respond_to? :asterisk
- # debug 'SKIP ASTERISKS: ' if @scanner.skip(ASTERISK_TAGS_SCAN)
- end
-
- # CLOSE
- elsif @tagstack.try_close_class(tag_class)
- #debug 'closing'
- # GARBAGE
- else
- return
- end
-
- true
- end
-
- def handle_asterisk tag_start, stars
- #debug 'ASTERISK: ' + stars.to_s
- # rule for asterisk tags: they belong to the last tag
- # that handles them. tags opened after this tag are closed.
- # if no open tag uses them, all are closed.
- tag = @tagstack.close_all_until { |tag| tag.respond_to? :asterisk }
- unless tag and tag.asterisk stars, @scanner
- garbage_out tag_start
- end
- end
-
- def handle_special_content tag
- scanned = @scanner.scan_until(tag.closing_tag)
- if scanned
- scanned.slice!(-(@scanner.matched.size)..-1)
- else
- scanned = @scanner.scan(/.*/m).to_s
- end
- #debug 'SPECIAL CONTENT: ' + scanned
- tag.handle_content(scanned)
- end
-
- def unescape text
- # input: correctly formatted quoted string (without the quotes)
- text.gsub(/\\(?:(["\\])|.)/) { $1 or $& }
- end
-
-
- # MAGIC FEAUTURES
-
- URL_PATTERN = /(?:(?:www|ftp)\.|(?>\w{3,}):\/\/)\S+/
- EMAIL_PATTERN = /(?>[\w\-_.]+)@[\w\-\.]+\.\w+/
-
- HAS_MAGIC = /[&@#{Smileys::SMILEY_START_CHARS}]|(?i:www|ftp)/
-
- MAGIC_PATTERN = Regexp.new('(\W|^)(%s)' %
- [Smileys::MAGIC_SMILEY_PATTERN, URL_PATTERN, EMAIL_PATTERN].map { |pattern|
- pattern.to_s
- }.join('|') )
-
- IS_SMILEY_PATTERN = Regexp.new('^%s' % Smileys::SMILEY_START_CHARSET.to_s )
- IS_URL_PATTERN = /^(?:(?i:www|ftp)\.|(?>\w+):\/\/)/
- URL_STARTS_WITH_PROTOCOL = /^\w+:\/\//
- IS_EMAIL_PATTERN = /^[\w\-_.]+@/
-
- def to_magic text
- # debug MAGIC_PATTERN.to_s
- text.gsub!(MAGIC_PATTERN) {
- magic = $2
- $1 + case magic
- when IS_SMILEY_PATTERN
- Smileys.smiley_to_img magic
- when IS_URL_PATTERN
- last = magic.slice_punctation! # no punctation in my URL
- href = magic
- href.insert(0, 'http://') unless magic =~ URL_STARTS_WITH_PROTOCOL
- '<a href="' + href + '">' + magic + '</a>' + last
- when IS_EMAIL_PATTERN
- last = magic.slice_punctation!
- '<a href="mailto:' + magic + '">' + magic + '</a>' + last
- else
- raise '{{{' + magic + '}}}'
- end
- }
- text
- end
-
- # handles smileys and urls
- def parse_magic html
- return html unless @do_magic
- scanner = StringScanner.new html
- out = ''
- while scanner.rest?
- if scanner.scan(/ < (?: a\s .*? <\/a> | pre\W .*? <\/pre> | [^>]* > ) /mx)
- out << scanner.matched
- elsif scanner.scan(/ [^<]+ /x)
- out << to_magic(scanner.matched)
-
- # this should never happen
- elsif scanner.scan(/./m)
- raise 'ERROR: else case reached'
- end
- end
- out
- end
- end # Parser
-end
-
-class String
- def slice_punctation!
- slice!(/[.:,!\?]+$/).to_s # return '' instead of nil
- end
-end
-
-#
-# = Grammar
-#
-# An implementation of common algorithms on grammars.
-#
-# This is used by Shinobu, a visualization tool for educating compiler-building.
-#
-# Thanks to Andreas Kunert for his wonderful LR(k) Pamphlet (German, see http://www.informatik.hu-berlin.de/~kunert/papers/lr-analyse), and Aho/Sethi/Ullman for their Dragon Book.
-#
-# Homepage:: http://shinobu.cYcnus.de (not existing yet)
-# Author:: murphy (Kornelius Kalnbach)
-# Copyright:: (cc) 2005 cYcnus
-# License:: GPL
-# Version:: 0.2.0 (2005-03-27)
-
-require 'set_hash'
-require 'ctype'
-require 'tools'
-require 'rules'
-require 'trace'
-
-require 'first'
-require 'follow'
-
-# = Grammar
-#
-# == Syntax
-#
-# === Rules
-#
-# Each line is a rule.
-# The syntax is
-#
-# left - right
-#
-# where +left+ and +right+ can be uppercase and lowercase letters,
-# and <code>-</code> can be any combination of <, >, - or whitespace.
-#
-# === Symbols
-#
-# Uppercase letters stand for meta symbols, lowercase for terminals.
-#
-# You can make epsilon-derivations by leaving <code><right></code> 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
- # <code>first["ABC"]</code> 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
- # <code>first["A"]</code> 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 = <<EOM
- Sorry, this example depends on the OpenGL extension. Please
- check the Ruby Application Archives for an appropriate
- download site.
-EOM
- missingDependency(MSG)
-end
-
-
-include Fox
-include Math
-
-Deg2Rad = Math::PI / 180
-
-D_MAX = 6
-SQUARE_SIZE = 2.0 / D_MAX
-SQUARE_DISTANCE = 4.0 / D_MAX
-AMPLITUDE = SQUARE_SIZE
-LAMBDA = D_MAX.to_f / 2
-
-class GLTestWindow < FXMainWindow
-
- # How often our timer will fire (in milliseconds)
- TIMER_INTERVAL = 500
-
- # Rotate the boxes when a timer message is received
- def onTimeout(sender, sel, ptr)
- @angle += 10.0
-# @size = 0.5 + 0.2 * Math.cos(Deg2Rad * @angle)
- drawScene()
- @timer = getApp().addTimeout(TIMER_INTERVAL, method(:onTimeout))
- end
-
- # Rotate the boxes when a chore message is received
- def onChore(sender, sel, ptr)
- @angle += 10.0
-# @angle %= 360.0
-# @size = 0.5 + 0.2 * Math.cos(Deg2Rad * @angle)
- drawScene()
- @chore = getApp().addChore(method(:onChore))
- end
-
- # Draw the GL scene
- def drawScene
- lightPosition = [15.0, 10.0, 5.0, 1.0]
- lightAmbient = [ 0.1, 0.1, 0.1, 1.0]
- lightDiffuse = [ 0.9, 0.9, 0.9, 1.0]
- redMaterial = [ 0.0, 0.0, 1.0, 1.0]
- blueMaterial = [ 0.0, 1.0, 0.0, 1.0]
-
- width = @glcanvas.width.to_f
- height = @glcanvas.height.to_f
- aspect = width/height
-
- # Make context current
- @glcanvas.makeCurrent()
-
- GL.Viewport(0, 0, @glcanvas.width, @glcanvas.height)
-
- GL.ClearColor(1.0/256, 0.0, 5.0/256, 1.0)
- GL.Clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT)
- GL.Enable(GL::DEPTH_TEST)
-
- GL.Disable(GL::DITHER)
-
- GL.MatrixMode(GL::PROJECTION)
- GL.LoadIdentity()
- GLU.Perspective(30.0, aspect, 1.0, 100.0)
-
- GL.MatrixMode(GL::MODELVIEW)
- GL.LoadIdentity()
- GLU.LookAt(5.0, 10.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
-
- GL.ShadeModel(GL::SMOOTH)
- GL.Light(GL::LIGHT0, GL::POSITION, lightPosition)
- GL.Light(GL::LIGHT0, GL::AMBIENT, lightAmbient)
- GL.Light(GL::LIGHT0, GL::DIFFUSE, lightDiffuse)
- GL.Enable(GL::LIGHT0)
- GL.Enable(GL::LIGHTING)
-
- GL.Rotated(0.1*@angle, 0.0, 1.0, 0.0)
- for x in -D_MAX..D_MAX
- for y in -D_MAX..D_MAX
- h1 = (x + y - 2).abs
- h2 = (y - x + 1).abs
- GL.PushMatrix
- c = [1, 0, 0, 1]
- GL.Material(GL::FRONT, GL::AMBIENT, c)
- GL.Material(GL::FRONT, GL::DIFFUSE, c)
-
- GL.Translated(
- y * SQUARE_DISTANCE,
- AMPLITUDE * h1,
- x * SQUARE_DISTANCE
- )
-
- GL.Begin(GL::TRIANGLE_STRIP)
- GL.Normal(1.0, 0.0, 0.0)
- GL.Vertex(-SQUARE_SIZE, +SQUARE_SIZE, -SQUARE_SIZE)
- GL.Vertex(-SQUARE_SIZE, +SQUARE_SIZE, +SQUARE_SIZE)
- GL.Vertex(+SQUARE_SIZE, +SQUARE_SIZE, -SQUARE_SIZE)
- GL.Vertex(+SQUARE_SIZE, +SQUARE_SIZE, +SQUARE_SIZE)
- GL.End
-
- GL.PopMatrix
-
- GL.PushMatrix
- c = [0, 0, 1, 1]
- GL.Material(GL::FRONT, GL::AMBIENT, c)
- GL.Material(GL::FRONT, GL::DIFFUSE, c)
-
- GL.Translated(
- y * SQUARE_DISTANCE,
- AMPLITUDE * h2,
- x * SQUARE_DISTANCE
- )
-
- GL.Begin(GL::TRIANGLE_STRIP)
- GL.Normal(1.0, 0.0, 0.0)
- GL.Vertex(-SQUARE_SIZE, +SQUARE_SIZE, -SQUARE_SIZE)
- GL.Vertex(-SQUARE_SIZE, +SQUARE_SIZE, +SQUARE_SIZE)
- GL.Vertex(+SQUARE_SIZE, +SQUARE_SIZE, -SQUARE_SIZE)
- GL.Vertex(+SQUARE_SIZE, +SQUARE_SIZE, +SQUARE_SIZE)
- GL.End
-
- GL.PopMatrix
-
- GL.PushMatrix
- c = [0.0 + (x/10.0), 0.0 + (y/10.0), 0, 1]
- GL.Material(GL::FRONT, GL::AMBIENT, c)
- GL.Material(GL::FRONT, GL::DIFFUSE, c)
-
- GL.Translated(
- y * SQUARE_DISTANCE,
- 0,
- x * SQUARE_DISTANCE
- )
-
- GL.Begin(GL::TRIANGLE_STRIP)
- GL.Normal(1.0, 0.0, 0.0)
- GL.Vertex(-SQUARE_SIZE, +SQUARE_SIZE, -SQUARE_SIZE)
- GL.Vertex(-SQUARE_SIZE, +SQUARE_SIZE, +SQUARE_SIZE)
- GL.Vertex(+SQUARE_SIZE, +SQUARE_SIZE, -SQUARE_SIZE)
- GL.Vertex(+SQUARE_SIZE, +SQUARE_SIZE, +SQUARE_SIZE)
- GL.End
-
- GL.PopMatrix
- end
- end
-
- # Swap if it is double-buffered
- if @glvisual.isDoubleBuffer
- @glcanvas.swapBuffers
- end
-
- # Make context non-current
- @glcanvas.makeNonCurrent
- end
-
- def initialize(app)
- # Invoke the base class initializer
- super(app, "OpenGL Test Application", nil, nil, DECOR_ALL, 0, 0, 1024, 768)
-
- # Construct the main window elements
- frame = FXHorizontalFrame.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y)
- frame.padLeft, frame.padRight = 0, 0
- frame.padTop, frame.padBottom = 0, 0
-
- # Left pane to contain the glcanvas
- glcanvasFrame = FXVerticalFrame.new(frame,
- LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT)
- glcanvasFrame.padLeft, glcanvasFrame.padRight = 10, 10
- glcanvasFrame.padTop, glcanvasFrame.padBottom = 10, 10
-
- # Label above the glcanvas
- FXLabel.new(glcanvasFrame, "OpenGL Canvas Frame", nil,
- JUSTIFY_CENTER_X|LAYOUT_FILL_X)
-
- # Horizontal divider line
- FXHorizontalSeparator.new(glcanvasFrame, SEPARATOR_GROOVE|LAYOUT_FILL_X)
-
- # Drawing glcanvas
- glpanel = FXVerticalFrame.new(glcanvasFrame, (FRAME_SUNKEN|FRAME_THICK|
- LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT))
- glpanel.padLeft, glpanel.padRight = 0, 0
- glpanel.padTop, glpanel.padBottom = 0, 0
-
- # A visual to draw OpenGL
- @glvisual = FXGLVisual.new(getApp(), VISUAL_DOUBLEBUFFER)
-
- # Drawing glcanvas
- @glcanvas = FXGLCanvas.new(glpanel, @glvisual, nil, 0,
- LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT)
- @glcanvas.connect(SEL_PAINT) {
- drawScene
- }
- @glcanvas.connect(SEL_CONFIGURE) {
- if @glcanvas.makeCurrent
- GL.Viewport(0, 0, @glcanvas.width, @glcanvas.height)
- @glcanvas.makeNonCurrent
- end
- }
-
- # Right pane for the buttons
- buttonFrame = FXVerticalFrame.new(frame, LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT)
- buttonFrame.padLeft, buttonFrame.padRight = 10, 10
- buttonFrame.padTop, buttonFrame.padBottom = 10, 10
-
- # Label above the buttons
- FXLabel.new(buttonFrame, "Button Frame", nil,
- JUSTIFY_CENTER_X|LAYOUT_FILL_X)
-
- # Horizontal divider line
- FXHorizontalSeparator.new(buttonFrame, SEPARATOR_RIDGE|LAYOUT_FILL_X)
-
- # Spin according to timer
- spinTimerBtn = FXButton.new(buttonFrame,
- "Spin &Timer\tSpin using interval timers\nNote the app
- blocks until the interal has elapsed...", nil,
- nil, 0, FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT)
- spinTimerBtn.padLeft, spinTimerBtn.padRight = 10, 10
- spinTimerBtn.padTop, spinTimerBtn.padBottom = 5, 5
- spinTimerBtn.connect(SEL_COMMAND) {
- @spinning = true
- @timer = getApp().addTimeout(TIMER_INTERVAL, method(:onTimeout))
- }
- spinTimerBtn.connect(SEL_UPDATE) { |sender, sel, ptr|
- @spinning ? sender.disable : sender.enable
- }
-
- # Spin according to chore
- spinChoreBtn = FXButton.new(buttonFrame,
- "Spin &Chore\tSpin as fast as possible using chores\nNote even though the
- app is very responsive, it never blocks;\nthere is always something to
- do...", nil,
- nil, 0, FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT)
- spinChoreBtn.padLeft, spinChoreBtn.padRight = 10, 10
- spinChoreBtn.padTop, spinChoreBtn.padBottom = 5, 5
- spinChoreBtn.connect(SEL_COMMAND) {
- @spinning = true
- @chore = getApp().addChore(method(:onChore))
- }
- spinChoreBtn.connect(SEL_UPDATE) { |sender, sel, ptr|
- @spinning ? sender.disable : sender.enable
- }
-
- # Stop spinning
- stopBtn = FXButton.new(buttonFrame,
- "&Stop Spin\tStop this mad spinning, I'm getting dizzy", nil,
- nil, 0, FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT)
- stopBtn.padLeft, stopBtn.padRight = 10, 10
- stopBtn.padTop, stopBtn.padBottom = 5, 5
- stopBtn.connect(SEL_COMMAND) {
- @spinning = false
- if @timer
- getApp().removeTimeout(@timer)
- @timer = nil
- end
- if @chore
- getApp().removeChore(@chore)
- @chore = nil
- end
- }
- stopBtn.connect(SEL_UPDATE) { |sender, sel, ptr|
- @spinning ? sender.enable : sender.disable
- }
-
- # Exit button
- exitBtn = FXButton.new(buttonFrame, "&Exit\tExit the application", nil,
- getApp(), FXApp::ID_QUIT,
- FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT)
- exitBtn.padLeft, exitBtn.padRight = 10, 10
- exitBtn.padTop, exitBtn.padBottom = 5, 5
-
- # Make a tooltip
- FXTooltip.new(getApp())
-
- # Initialize private variables
- @spinning = false
- @chore = nil
- @timer = nil
- @angle = 0.0
- @size = 0.5
- end
-
- # Create and initialize
- def create
- super
- show(PLACEMENT_SCREEN)
- end
-end
-
-if __FILE__ == $0
- # Construct the application
- application = FXApp.new("GLTest", "FoxTest")
-
- # To ensure that the chores-based spin will run as fast as possible,
- # we can disable the chore in FXRuby's event loop that tries to schedule
- # other threads. This is OK for this program because there aren't any
- # other Ruby threads running.
-
- #application.disableThreads
-
- # Construct the main window
- GLTestWindow.new(application)
-
- # Create the app's windows
- application.create
-
- # Run the application
- application.run
-end
-
-class Facelet
- attr_accessor :color
- def initialize(color)
- @color = color
- end
-
- def to_s
- @color
- end
-end
-
-class Edge
- attr_accessor :facelets, :colors
-
- def initialize(facelets)
- @facelets = facelets
- @colors = @facelets.map { |fl| fl.color }
- end
-
- def apply(edge)
- @facelets.each_with_index { |fl, i|
- fl.color = edge.colors[i]
- }
- end
-
- def inspect
- "\n%s %s\n%s %s %s" % facelets
- end
-end
-
-class Side
- attr_reader :num, :facelets
- attr_accessor :sides
-
- def initialize(num)
- @num = num
- @sides = []
- @facelets = []
- @fl_by_side = {}
- end
-
- # facelets & sides
- # 0
- # 0 1 2
- # 3 3 4 5 1
- # 6 7 8
- # 2
-
- def facelets=(facelets)
- @facelets = facelets.map { |c| Facelet.new(c) }
- init_facelet 0, 3,0
- init_facelet 1, 0
- init_facelet 2, 0,1
- init_facelet 3, 3
- init_facelet 5, 1
- init_facelet 6, 2,3
- init_facelet 7, 2
- init_facelet 8, 1,2
- end
-
- def <=>(side)
- self.num <=> side.num
- end
-
- def init_facelet(pos, *side_nums)
- sides = side_nums.map { |num| @sides[num] }.sort
- @fl_by_side[sides] = pos
- end
-
- def []=(color, *sides)
- @facelets[@fl_by_side[sides.sort]].color = color
- end
-
- def values_at(*sides)
- sides.map { |sides| @facelets[@fl_by_side[sides.sort]] }
- end
-
- def inspect(range=nil)
- if range
- @facelets.values_at(*(range.to_a)).join(' ')
- else
- <<-EOS.gsub(/\d/) { |num| @facelets[num.to_i] }.gsub(/[ABCD]/) { |side| @sides[side[0]-?A].num.to_s }
- A
- 0 1 2
- D 3 4 5 B
- 6 7 8
- C
- EOS
- end
- end
-
- def get_edge(side)
- trio = (-1..1).map { |x| (side + x) % 4 }
- prev_side, this_side, next_side = @sides.values_at(*trio)
- e = Edge.new(
- self .values_at( [this_side], [this_side, next_side] ) +
- this_side.values_at( [self, prev_side], [self ], [self, next_side] )
- )
- #puts 'Edge created for side %d: ' % side + e.inspect
- e
- end
-
- def turn(dir)
- #p 'turn side %d in %d' % [num, dir]
- edges = (0..3).map { |n| get_edge n }
- for i in 0..3
- edges[i].apply edges[(i-dir) % 4]
- end
- end
-end
-
-class Cube
- def initialize
- @sides = []
- %w(left front right back top bottom).each_with_index { |side, i|
- eval("@sides[#{i}] = @#{side} = Side.new(#{i})")
- }
- @left.sides = [@top, @front, @bottom, @back]
- @front.sides = [@top, @right, @bottom, @left]
- @right.sides = [@top, @back, @bottom, @front]
- @back.sides = [@top, @left, @bottom, @right]
- @top.sides = [@back, @right, @front, @left]
- @bottom.sides = [@front, @right, @back, @left]
- end
-
- def read_facelets(fs)
- pattern = Regexp.new(<<-EOP.gsub(/\w/, '\w').gsub(/\s+/, '\s*'))
- (w w w)
- (w w w)
- (w w w)
-(r r r) (g g g) (b b b) (o o o)
-(r r r) (g g g) (b b b) (o o o)
-(r r r) (g g g) (b b b) (o o o)
- (y y y)
- (y y y)
- (y y y)
- EOP
- md = pattern.match(fs).to_a
-
- @top.facelets = parse_facelets(md.values_at(1,2,3))
- @left.facelets = parse_facelets(md.values_at(4,8,12))
- @front.facelets = parse_facelets(md.values_at(5,9,13))
- @right.facelets = parse_facelets(md.values_at(6,10,14))
- @back.facelets = parse_facelets(md.values_at(7,11,15))
- @bottom.facelets = parse_facelets(md.values_at(16,17,18))
- end
-
- def turn(side, dir)
- #p 'turn %d in %d' % [side, dir]
- @sides[side].turn(dir)
- #puts inspect
- end
-
- def inspect
- <<-EOF.gsub(/(\d):(\d)-(\d)/) { @sides[$1.to_i].inspect(Range.new($2.to_i, $3.to_i)) }
- 4:0-2
- 4:3-5
- 4:6-8
-0:0-2 1:0-2 2:0-2 3:0-2
-0:3-5 1:3-5 2:3-5 3:3-5
-0:6-8 1:6-8 2:6-8 3:6-8
- 5:0-2
- 5:3-5
- 5:6-8
- EOF
- end
-
-private
- def parse_facelets(rows)
- rows.join.delete(' ').split(//)
- end
-end
-
-#$stdin = DATA
-
-gets.to_i.times do |i|
- puts "Scenario ##{i+1}:"
- fs = ''
- 9.times { fs << gets }
- cube = Cube.new
- cube.read_facelets fs
- gets.to_i.times do |t|
- side, dir = gets.split.map {|s| s.to_i}
- cube.turn(side, dir)
- end
- puts cube.inspect
- puts
-end
-
-# 2004 by murphy <korny@cYcnus.de>
-# GPL
-class Scenario
- class TimePoint
- attr_reader :data
- def initialize *data
- @data = data
- end
-
- def [] i
- @data[i] or 0
- end
-
- include Comparable
- def <=> tp
- r = 0
- [@data.size, tp.data.size].max.times do |i|
- r = self[i] <=> tp[i]
- return r if r.nonzero?
- end
- 0
- end
-
- def - tp
- r = []
- [@data.size, tp.data.size].max.times do |i|
- r << self[i] - tp[i]
- end
- r
- end
-
- def inspect
- # 01/01/1800 00:00:00
- '%02d/%02d/%04d %02d:%02d:%02d' % @data.values_at(1, 2, 0, 3, 4, 5)
- end
- end
-
- ONE_HOUR = TimePoint.new 0, 0, 0, 1, 0, 0
-
- APPOINTMENT_PATTERN = /
- ( \d{4} ) \s ( \d{2} ) \s ( \d{2} ) \s ( \d{2} ) \s ( \d{2} ) \s ( \d{2} ) \s
- ( \d{4} ) \s ( \d{2} ) \s ( \d{2} ) \s ( \d{2} ) \s ( \d{2} ) \s ( \d{2} )
- /x
-
- def initialize io
- @team_size = io.gets.to_i
- @data = [ [TimePoint.new(1800, 01, 01, 00, 00, 00), @team_size] ]
- @team_size.times do # each team member
- io.gets.to_i.times do # each appointment
- m = APPOINTMENT_PATTERN.match io.gets
- @data << [TimePoint.new(*m.captures[0,6].map { |x| x.to_i }), -1]
- @data << [TimePoint.new(*m.captures[6,6].map { |x| x.to_i }), +1]
- end
- end
- @data << [TimePoint.new(2200, 01, 01, 00, 00, 00), -@team_size]
- end
-
- def print_time_plan
- n = 0
- appointment = nil
- no_appointment = true
- @data.sort_by { |x| x[0] }.each do |x|
- tp, action = *x
- n += action
- # at any time during the meeting, at least two team members need to be there
- # and at most one team member is allowed to be absent
- if n >= 2 and (@team_size - n) <= 1
- appointment ||= tp
- else
- if appointment
- # the meeting should be at least one hour in length
- if TimePoint.new(*(tp - appointment)) >= ONE_HOUR
- puts 'appointment possible from %p to %p' % [appointment, tp]
- no_appointment = false
- end
- appointment = false
- end
- end
- end
- puts 'no appointment possible' if no_appointment
- end
-end
-
-# read the data
-DATA.gets.to_i.times do |si| # each scenario
- puts 'Scenario #%d:' % (si + 1)
- sc = Scenario.new DATA
- sc.print_time_plan
- puts
-end
-
-#__END__
-2
-3
-3
-2002 06 28 15 00 00 2002 06 28 18 00 00 TUD Contest Practice Session
-2002 06 29 10 00 00 2002 06 29 15 00 00 TUD Contest
-2002 11 15 15 00 00 2002 11 17 23 00 00 NWERC Delft
-4
-2002 06 25 13 30 00 2002 06 25 15 30 00 FIFA World Cup Semifinal I
-2002 06 26 13 30 00 2002 06 26 15 30 00 FIFA World Cup Semifinal II
-2002 06 29 13 00 00 2002 06 29 15 00 00 FIFA World Cup Third Place
-2002 06 30 13 00 00 2002 06 30 15 00 00 FIFA World Cup Final
-1
-2002 06 01 00 00 00 2002 06 29 18 00 00 Preparation of Problem Set
-2
-1
-1800 01 01 00 00 00 2200 01 01 00 00 00 Solving Problem 8
-0
-
-require 'token_consts'
-require 'symbol'
-require 'ctype'
-require 'error'
-
-class Fixnum
- # Treat char as a digit and return it's value as Fixnum.
- # Returns nonsense for non-digits.
- # Examples:
- # <code>
- # RUBY_VERSION[0].digit == '1.8.2'[0].digit == 1
- # </code>
- #
- # <code>
- # ?6.digit == 6
- # </code>
- #
- # <code>
- # ?A.digit == 17
- # </code>
- def digit
- self - ?0
- end
-end
-
-##
-# Stellt einen einfachen Scanner für 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
- 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 zurück.
- # @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 Schlüsselwort zu erkennen.
- # Sollte dabei ein Keyword gefunden werden, so gibt er ein PascalSymbol-Objekt zurück, das
- # das entsprechende Keyword repräsentiert. Ansonsten besteht die Rückgabe 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 endgültige 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.
- # <BR>
- # Treten dabei kein Punkt oder ein E auf, so gibt diese Methode ein SymbolIntCon-Objekt
- # zurück, ansonsten (reelle Zahl) ein SymbolRealCon-Objekt. Beide Symbole enthalten
- # jeweils die Zahlwerte.
- # <BR>
- # Anmerkung: Diese Funktion ist mit Hilfe der Java/Ruby-API deutlich leichter zu realisieren.
- # Sie wurde dennoch so implementiert, um den Algorithmus zu demonstrieren
- # @see symbol
- # @return SymbolIntcon- oder SymbolRealcon-Objekt, das den Zahlwert enthält
- def number
- is_integer = true
- integer_too_long = false
- exponent = 0
- exp_counter = -1
- exp_sign = 1
-
- integer_mantisse = @current_char.digit
-
- while (@next_char.digit? and integer_mantisse < MAXINT_DIV_10) or
- (integer_mantisse == MAXINT_DIV_10 and @next_char.digit <= MAXINT_MOD_10)
- integer_mantisse *= 10
- integer_mantisse += @next_char.digit
- read_next_char
- end
-
- real_mantisse = integer_mantisse
-
- while @next_char.digit?
- integer_too_long = true
- real_mantisse *= 10
- real_mantisse += @next_char.digit
- read_next_char
- end
- if @next_char == ?.
- read_next_char
- is_integer = false
- unless @next_char.digit?
- Error.error 101, @line, @pos
- end
- while @next_char.digit?
- real_mantisse += @next_char.digit * (10 ** exp_counter)
- read_next_char
- exp_counter -= 1
- end
- end
- if @next_char == ?E
- is_integer = false
- read_next_char
- if @next_char == ?-
- exp_sign = -1
- read_next_char
- end
- unless @next_char.digit?
- Error.error 101, @line, @pos
- end
- while @next_char.digit?
- exponent *= 10
- exponent += @next_char.digit
- read_next_char
- end
- end
-
- if is_integer
- if integer_too_long
- Error.error 102, @line, @pos
- end
- SymbolIntcon.new integer_mantisse
- else
- SymbolRealcon.new real_mantisse * (10 ** (exp_sign * exponent))
- end
- end
-
- ##
- # Sorgt für ein Überlesen von Kommentaren.
- # Es werden einfach alle Zeichen bis zu einer schließenden Klammer eingelesen
- # und verworfen.
- def comment
- while @current_char != ?}
- forbid_eop
- new_line if @current_char == ?\n
- read_next_char
- end
- end
-
- def new_line
- @line += 1
- @pos = 0
- end
-
- def forbid_eop
- if eop?
- Error.error 103, @line, @pos
- end
- exit
- end
-
- def eop?
- @current_char.nil?
- end
-end
-
-##
-# Läßt ein Testprogramm ablaufen.
-# Dieses erzeugt sich ein Scanner-Objekt und ruft an diesem kontinuierlich bis zum Dateiende
-# get_symbol auf.
-if $0 == __FILE__
- scan = Scanner.new(File.new(ARGV[0] || 'test.pas'))
- loop do
- c = scan.get_symbol
- puts c
- break if c.typ == TokenConsts::EOP
- end
-end
-# -*- ruby -*-
-
-# Local variables:
-# indent-tabs-mode: nil
-# ruby-indent-level: 4
-# End:
-
-# @@PLEAC@@_NAME
-# @@SKIP@@ Ruby
-
-# @@PLEAC@@_WEB
-# @@SKIP@@ http://www.ruby-lang.org
-
-
-# @@PLEAC@@_1.0
-string = '\n' # two characters, \ and an n
-string = 'Jon \'Maddog\' Orwant' # literal single quotes
-
-string = "\n" # a "newline" character
-string = "Jon \"Maddog\" Orwant" # literal double quotes
-
-string = %q/Jon 'Maddog' Orwant/ # literal single quotes
-
-string = %q[Jon 'Maddog' Orwant] # literal single quotes
-string = %q{Jon 'Maddog' Orwant} # literal single quotes
-string = %q(Jon 'Maddog' Orwant) # literal single quotes
-string = %q<Jon 'Maddog' Orwant> # literal single quotes
-
-a = <<"EOF"
-This is a multiline here document
-terminated by EOF on a line by itself
-EOF
-
-
-# @@PLEAC@@_1.1
-value = string[offset,count]
-value = string[offset..-1]
-
-string[offset,count] = newstring
-string[offset..-1] = newtail
-
-# in Ruby we can also specify intervals by their two offsets
-value = string[offset..offs2]
-string[offset..offs2] = newstring
-
-leading, s1, s2, trailing = data.unpack("A5 x3 A8 A8 A*")
-
-fivers = string.unpack("A5" * (string.length/5))
-
-chars = string.unpack("A1" * string.length)
-
-string = "This is what you have"
-# +012345678901234567890 Indexing forwards (left to right)
-# 109876543210987654321- Indexing backwards (right to left)
-# note that 0 means 10 or 20, etc. above
-
-first = string[0, 1] # "T"
-start = string[5, 2] # "is"
-rest = string[13..-1] # "you have"
-last = string[-1, 1] # "e"
-end_ = string[-4..-1] # "have"
-piece = string[-8, 3] # "you"
-
-string[5, 2] = "wasn't" # change "is" to "wasn't"
-string[-12..-1] = "ondrous" # "This wasn't wondrous"
-string[0, 1] = "" # delete first character
-string[-10..-1] = "" # delete last 10 characters
-
-if string[-10..-1] =~ /pattern/
- puts "Pattern matches in last 10 characters"
-end
-
-string[0, 5].gsub!(/is/, 'at')
-
-a = "make a hat"
-a[0, 1], a[-1, 1] = a[-1, 1], a[0, 1]
-
-a = "To be or not to be"
-b = a.unpack("x6 A6")
-
-b, c = a.unpack("x6 A2 X5 A2")
-puts "#{b}\n#{c}\n"
-
-def cut2fmt(*args)
- template = ''
- lastpos = 1
- for place in args
- template += "A" + (place - lastpos).to_s + " "
- lastpos = place
- end
- template += "A*"
- return template
-end
-
-fmt = cut2fmt(8, 14, 20, 26, 30)
-
-
-# @@PLEAC@@_1.2
-# careful! "b is true" doesn't mean "b != 0" (0 is true in Ruby)
-# thus no problem of "defined" later since only nil is false
-# the following sets to `c' if `b' is nil or false
-a = b || c
-
-# if you need Perl's behaviour (setting to `c' if `b' is 0) the most
-# effective way is to use Numeric#nonzero? (thanks to Dave Thomas!)
-a = b.nonzero? || c
-
-# you will still want to use defined? in order to test
-# for scope existence of a given object
-a = defined?(b) ? b : c
-
-dir = ARGV.shift || "/tmp"
-
-
-# @@PLEAC@@_1.3
-v1, v2 = v2, v1
-
-alpha, beta, production = %w(January March August)
-alpha, beta, production = beta, production, alpha
-
-
-# @@PLEAC@@_1.4
-num = char[0]
-char = num.chr
-
-# Ruby also supports having a char from character constant
-num = ?r
-
-char = sprintf("%c", num)
-printf("Number %d is character %c\n", num, num)
-
-ascii = string.unpack("C*")
-string = ascii.pack("C*")
-
-hal = "HAL"
-ascii = hal.unpack("C*")
-# We can't use Array#each since we can't mutate a Fixnum
-ascii.collect! { |i|
- i + 1 # add one to each ASCII value
-}
-ibm = ascii.pack("C*")
-puts ibm
-
-
-# @@PLEAC@@_1.5
-array = string.split('')
-
-array = string.unpack("C*")
-
-string.scan(/./) { |b|
- # do something with b
-}
-
-string = "an apple a day"
-print "unique chars are: ", string.split('').uniq.sort, "\n"
-
-sum = 0
-for ascval in string.unpack("C*") # or use Array#each for a pure OO style :)
- sum += ascval
-end
-puts "sum is #{sum & 0xffffffff}" # since Ruby will go Bignum if necessary
-
-# @@INCLUDE@@ include/ruby/slowcat.rb
-
-
-# @@PLEAC@@_1.6
-revbytes = string.reverse
-
-revwords = string.split(" ").reverse.join(" ")
-
-revwords = string.split(/(\s+)/).reverse.join
-
-# using the fact that IO is Enumerable, you can directly "select" it
-long_palindromes = File.open("/usr/share/dict/words").
- select { |w| w.chomp!; w.reverse == w && w.length > 5 }
-
-
-# @@PLEAC@@_1.7
-while string.sub!("\t+") { ' ' * ($&.length * 8 - $`.length % 8) }
-end
-
-
-# @@PLEAC@@_1.8
-'You owe #{debt} to me'.gsub(/\#{(\w+)}/) { eval($1) }
-
-rows, cols = 24, 80
-text = %q(I am #{rows} high and #{cols} long)
-text.gsub!(/\#{(\w+)}/) { eval("#{$1}") }
-puts text
-
-'I am 17 years old'.gsub(/\d+/) { 2 * $&.to_i }
-
-
-# @@PLEAC@@_1.9
-e = "bo peep".upcase
-e.downcase!
-e.capitalize!
-
-"thIS is a loNG liNE".gsub!(/\w+/) { $&.capitalize }
-
-
-# @@PLEAC@@_1.10
-"I have #{n+1} guanacos."
-print "I have ", n+1, " guanacos."
-
-
-# @@PLEAC@@_1.11
-var = <<'EOF'.gsub(/^\s+/, '')
- your text
- goes here
-EOF
-
-
-# @@PLEAC@@_1.12
-string = "Folding and splicing is the work of an editor,\n"+
- "not a mere collection of silicon\n"+
- "and\n"+
- "mobile electrons!"
-
-def wrap(str, max_size)
- all = []
- line = ''
- for l in str.split
- if (line+l).length >= max_size
- all.push(line)
- line = ''
- end
- line += line == '' ? l : ' ' + l
- end
- all.push(line).join("\n")
-end
-
-print wrap(string, 20)
-#=> Folding and
-#=> splicing is the
-#=> work of an editor,
-#=> not a mere
-#=> collection of
-#=> silicon and mobile
-#=> electrons!
-
-
-# @@PLEAC@@_1.13
-string = %q(Mom said, "Don't do that.")
-string.gsub(/['"]/) { '\\'+$& }
-string.gsub(/['"]/, '\&\&')
-string.gsub(/[^A-Z]/) { '\\'+$& }
-"is a test!".gsub(/\W/) { '\\'+$& } # no function like quotemeta?
-
-
-# @@PLEAC@@_1.14
-string.strip!
-
-
-# @@PLEAC@@_1.15
-def parse_csv(text)
- new = text.scan(/"([^\"\\]*(?:\\.[^\"\\]*)*)",?|([^,]+),?|,/)
- new << nil if text[-1] == ?,
- new.flatten.compact
-end
-
-line = %q<XYZZY,"","O'Reilly, Inc","Wall, Larry","a \"glug\" bit,",5,"Error, Core Dumped">
-fields = parse_csv(line)
-fields.each_with_index { |v,i|
- print "#{i} : #{v}\n";
-}
-
-
-# @@PLEAC@@_1.16
-# Use the soundex.rb Library from Michael Neumann.
-# http://www.s-direktnet.de/homepages/neumann/rb_prgs/Soundex.rb
-require 'Soundex'
-
-code = Text::Soundex.soundex(string)
-codes = Text::Soundex.soundex(array)
-
-# substitution function for getpwent():
-# returns an array of user entries,
-# each entry contains the username and the full name
-def login_names
- result = []
- File.open("/etc/passwd") { |file|
- file.each_line { |line|
- next if line.match(/^#/)
- cols = line.split(":")
- result.push([cols[0], cols[4]])
- }
- }
- result
-end
-
-puts "Lookup user: "
-user = STDIN.gets
-user.chomp!
-exit unless user
-name_code = Text::Soundex.soundex(user)
-
-splitter = Regexp.new('(\w+)[^,]*\b(\w+)')
-for username, fullname in login_names do
- firstname, lastname = splitter.match(fullname)[1,2]
- if name_code == Text::Soundex.soundex(username)
- || name_code == Text::Soundex.soundex(firstname)
- || name_code == Text::Soundex.soundex(lastname)
- then
- puts "#{username}: #{firstname} #{lastname}"
- end
-end
-
-
-# @@PLEAC@@_1.17
-# @@INCLUDE@@ include/ruby/fixstyle.rb
-
-
-# @@PLEAC@@_1.18
-# @@INCLUDE@@ include/ruby/psgrep.rb
-
-
-# @@PLEAC@@_2.1
-# Matz tells that you can use Integer() for strict checked conversion.
-Integer("abc")
-#=> `Integer': invalid value for Integer: "abc" (ArgumentError)
-Integer("567")
-#=> 567
-
-# You may use Float() for floating point stuff
-Integer("56.7")
-#=> `Integer': invalid value for Integer: "56.7" (ArgumentError)
-Float("56.7")
-#=> 56.7
-
-# You may also use a regexp for that
-if string =~ /^[+-]?\d+$/
- p 'is an integer'
-else
- p 'is not'
-end
-
-if string =~ /^-?(?:\d+(?:\.\d*)?|\.\d+)$/
- p 'is a decimal number'
-else
- p 'is not'
-end
-
-
-# @@PLEAC@@_2.2
-# equal(num1, num2, accuracy) : returns true if num1 and num2 are
-# equal to accuracy number of decimal places
-def equal(i, j, a)
- sprintf("%.#{a}g", i) == sprintf("%.#{a}g", j)
-end
-
-wage = 536 # $5.36/hour
-week = 40 * wage # $214.40
-printf("One week's wage is: \$%.2f\n", week/100.0)
-
-
-# @@PLEAC@@_2.3
-num.round # rounds to integer
-
-a = 0.255
-b = sprintf("%.2f", a)
-print "Unrounded: #{a}\nRounded: #{b}\n"
-printf "Unrounded: #{a}\nRounded: %.2f\n", a
-
-print "number\tint\tfloor\tceil\n"
-a = [ 3.3 , 3.5 , 3.7, -3.3 ]
-for n in a
- printf("% .1f\t% .1f\t% .1f\t% .1f\n", # at least I don't fake my output :)
- n, n.to_i, n.floor, n.ceil)
-end
-
-
-# @@PLEAC@@_2.4
-def dec2bin(n)
- [n].pack("N").unpack("B32")[0].sub(/^0+(?=\d)/, '')
-end
-
-def bin2dec(n)
- [("0"*32+n.to_s)[-32..-1]].pack("B32").unpack("N")[0]
-end
-
-
-# @@PLEAC@@_2.5
-for i in x .. y
- # i is set to every integer from x to y, inclusive
-end
-
-x.step(y,7) { |i|
- # i is set to every integer from x to y, stepsize = 7
-}
-
-print "Infancy is: "
-(0..2).each { |i|
- print i, " "
-}
-print "\n"
-
-
-# @@PLEAC@@_2.6
-# We can add conversion methods to the Integer class,
-# this makes a roman number just a representation for normal numbers.
-class Integer
-
- @@romanlist = [["M", 1000],
- ["CM", 900],
- ["D", 500],
- ["CD", 400],
- ["C", 100],
- ["XC", 90],
- ["L", 50],
- ["XL", 40],
- ["X", 10],
- ["IX", 9],
- ["V", 5],
- ["IV", 4],
- ["I", 1]]
-
- def to_roman
- remains = self
- roman = ""
- for sym, num in @@romanlist
- while remains >= num
- remains -= num
- roman << sym
- end
- end
- roman
- end
-
- def Integer.from_roman(roman)
- ustr = roman.upcase
- sum = 0
- for entry in @@romanlist
- sym, num = entry[0], entry[1]
- while sym == ustr[0, sym.length]
- sum += num
- ustr.slice!(0, sym.length)
- end
- end
- sum
- end
-
-end
-
-
-roman_fifteen = 15.to_roman
-puts "Roman for fifteen is #{roman_fifteen}"
-i = Integer.from_roman(roman_fifteen)
-puts "Converted back, #{roman_fifteen} is #{i}"
-
-# check
-for i in (1..3900)
- r = i.to_roman
- j = Integer.from_roman(r)
- if i != j
- puts "error: #{i} : #{r} - #{j}"
- end
-end
-
-
-# @@PLEAC@@_2.7
-random = rand(y-x+1)+x
-
-chars = ["A".."Z","a".."z","0".."9"].collect { |r| r.to_a }.join + %q(!@$%^&*)
-password = (1..8).collect { chars[rand(chars.size)] }.pack("C*")
-
-
-# @@PLEAC@@_2.8
-srand # uses a combination of the time, the process id, and a sequence number
-srand(val) # for repeatable behaviour
-
-
-# @@PLEAC@@_2.9
-# from the randomr lib:
-# http://raa.ruby-lang.org/project/randomr/
-----> http://raa.ruby-lang.org/project/randomr/
-
-require 'random/mersenne_twister'
-mers = Random::MersenneTwister.new 123456789
-puts mers.rand(0) # 0.550321932544541
-puts mers.rand(10) # 2
-
-# using online sources of random data via the realrand package:
-# http://raa.ruby-lang.org/project/realrand/
-# **Note**
-# The following online services are used in this package:
-# http://www.random.org - source: atmospheric noise
-# http://www.fourmilab.ch/hotbits - source: radioactive decay timings
-# http://random.hd.org - source: entropy from local and network noise
-# Please visit the sites and respect the rules of each service.
-
-require 'random/online'
-
-generator1 = Random::RandomOrg.new
-puts generator1.randbyte(5).join(",")
-puts generator1.randnum(10, 1, 6).join(",") # Roll dice 10 times.
-
-generator2 = Random::FourmiLab.new
-puts generator2.randbyte(5).join(",")
-# randnum is not supported.
-
-generator3 = Random::EntropyPool.new
-puts generator3.randbyte(5).join(",")
-# randnum is not supported.
-
-
-# @@PLEAC@@_2.10
-def gaussian_rand
- begin
- u1 = 2 * rand() - 1
- u2 = 2 * rand() - 1
- w = u1*u1 + u2*u2
- end while (w >= 1)
- w = Math.sqrt((-2*Math.log(w))/w)
- [ u2*w, u1*w ]
-end
-
-mean = 25
-sdev = 2
-salary = gaussian_rand[0] * sdev + mean
-printf("You have been hired at \$%.2f\n", salary)
-
-
-# @@PLEAC@@_2.11
-def deg2rad(d)
- (d/180.0)*Math::PI
-end
-
-def rad2deg(r)
- (r/Math::PI)*180
-end
-
-
-# @@PLEAC@@_2.12
-sin_val = Math.sin(angle)
-cos_val = Math.cos(angle)
-tan_val = Math.tan(angle)
-
-# AFAIK Ruby's Math module doesn't provide acos/asin
-# While we're at it, let's also define missing hyperbolic functions
-module Math
- def Math.asin(x)
- atan2(x, sqrt(1 - x**2))
- end
- def Math.acos(x)
- atan2(sqrt(1 - x**2), x)
- end
- def Math.atan(x)
- atan2(x, 1)
- end
- def Math.sinh(x)
- (exp(x) - exp(-x)) / 2
- end
- def Math.cosh(x)
- (exp(x) + exp(-x)) / 2
- end
- def Math.tanh(x)
- sinh(x) / cosh(x)
- end
-end
-
-# The support for Complex numbers is not built-in
-y = Math.acos(3.7)
-#=> in `sqrt': square root for negative number (ArgumentError)
-
-# There is an implementation of Complex numbers in 'complex.rb' in current
-# Ruby distro, but it doesn't support atan2 with complex args, so it doesn't
-# solve this problem.
-
-
-# @@PLEAC@@_2.13
-log_e = Math.log(val)
-log_10 = Math.log10(val)
-
-def log_base(base, val)
- Math.log(val)/Math.log(base)
-end
-
-answer = log_base(10, 10_000)
-puts "log10(10,000) = #{answer}"
-
-
-# @@PLEAC@@_2.14
-require 'matrix.rb'
-
-a = Matrix[[3, 2, 3], [5, 9, 8]]
-b = Matrix[[4, 7], [9, 3], [8, 1]]
-c = a * b
-
-a.row_size
-a.column_size
-
-c.det
-a.transpose
-
-
-# @@PLEAC@@_2.15
-require 'complex.rb'
-require 'rational.rb'
-
-a = Complex(3, 5) # 3 + 5i
-b = Complex(2, -2) # 2 - 2i
-puts "c = #{a*b}"
-
-c = a * b
-d = 3 + 4*Complex::I
-
-printf "sqrt(#{d}) = %s\n", Math.sqrt(d)
-
-
-# @@PLEAC@@_2.16
-number = hexadecimal.hex
-number = octal.oct
-
-print "Gimme a number in decimal, octal, or hex: "
-num = gets.chomp
-exit unless defined?(num)
-num = num.oct if num =~ /^0/ # does both oct and hex
-printf "%d %x %o\n", num, num, num
-
-print "Enter file permission in octal: "
-permissions = gets.chomp
-raise "Exiting ...\n" unless defined?(permissions)
-puts "The decimal value is #{permissions.oct}"
-
-
-# @@PLEAC@@_2.17
-def commify(n)
- n.to_s =~ /([^\.]*)(\..*)?/
- int, dec = $1.reverse, $2 ? $2 : ""
- while int.gsub!(/(,|\.|^)(\d{3})(\d)/, '\1\2,\3')
- end
- int.reverse + dec
-end
-
-
-# @@PLEAC@@_2.18
-printf "It took %d hour%s\n", time, time == 1 ? "" : "s"
-
-# dunno if an equivalent to Lingua::EN::Inflect exists...
-
-
-# @@PLEAC@@_2.19
-#-----------------------------
-#!/usr/bin/ruby
-# bigfact - calculating prime factors
-def factorize(orig)
- factors = {}
- factors.default = 0 # return 0 instead nil if key not found in hash
- n = orig
- i = 2
- sqi = 4 # square of i
- while sqi <= n do
- while n.modulo(i) == 0 do
- n /= i
- factors[i] += 1
- # puts "Found factor #{i}"
- end
- # we take advantage of the fact that (i +1)**2 = i**2 + 2*i +1
- sqi += 2 * i + 1
- i += 1
- end
-
- if (n != 1) && (n != orig)
- factors[n] += 1
- end
- factors
-end
-
-def printfactorhash(orig, factorcount)
- print format("%-10d ", orig)
- if factorcount.length == 0
- print "PRIME"
- else
- # sorts after number, because the hash keys are numbers
- factorcount.sort.each { |factor,exponent|
- print factor
- if exponent > 1
- print "**", exponent
- end
- print " "
- }
- end
- puts
-end
-
-for arg in ARGV
- n = arg.to_i
- mfactors = factorize(n)
- printfactorhash(n, mfactors)
-end
-#-----------------------------
-
-
-# @@PLEAC@@_3.0
-puts Time.now
-
-print "Today is day ", Time.now.yday, " of the current year.\n"
-print "Today is day ", Time.now.day, " of the current month.\n"
-
-
-# @@PLEAC@@_3.1
-day, month, year = Time.now.day, Time.now.month, Time.now.year
-# or
-day, month, year = Time.now.to_a[3..5]
-
-tl = Time.now.localtime
-printf("The current date is %04d %02d %02d\n", tl.year, tl.month, tl.day)
-
-Time.now.localtime.strftime("%Y-%m-%d")
-
-
-# @@PLEAC@@_3.2
-Time.local(year, month, day, hour, minute, second).tv_sec
-Time.gm(year, month, day, hour, minute, second).tv_sec
-
-
-# @@PLEAC@@_3.3
-sec, min, hour, day, month, year, wday, yday, isdst, zone = Time.at(epoch_secs).to_a
-
-
-# @@PLEAC@@_3.4
-when_ = now + difference # now -> Time ; difference -> Numeric (delta in seconds)
-then_ = now - difference
-
-
-# @@PLEAC@@_3.5
-bree = 361535725
-nat = 96201950
-
-difference = bree - nat
-puts "There were #{difference} seconds between Nat and Bree"
-
-seconds = difference % 60
-difference = (difference - seconds) / 60
-minutes = difference % 60
-difference = (difference - minutes) / 60
-hours = difference % 24
-difference = (difference - hours) / 24
-days = difference % 7
-weeks = (difference - days) / 7
-
-puts "(#{weeks} weeks, #{days} days, #{hours}:#{minutes}:#{seconds})"
-
-
-# @@PLEAC@@_3.6
-monthday, weekday, yearday = date.mday, date.wday, date.yday
-
-# AFAIK the week number is not just a division since week boundaries are on sundays
-weeknum = d.strftime("%U").to_i + 1
-
-year = 1981
-month = "jun" # or `6' if you want to emulate a broken language
-day = 16
-t = Time.mktime(year, month, day)
-print "#{month}/#{day}/#{year} was a ", t.strftime("%A"), "\n"
-
-
-# @@PLEAC@@_3.7
-yyyy, mm, dd = $1, $2, $3 if "1998-06-25" =~ /(\d+)-(\d+)-(\d+)/
-
-epoch_seconds = Time.mktime(yyyy, mm, dd).tv_sec
-
-# dunno an equivalent to Date::Manip#ParseDate
-
-
-# @@PLEAC@@_3.8
-string = Time.at(epoch_secs)
-Time.at(1234567890).gmtime # gives: Fri Feb 13 23:31:30 UTC 2009
-
-time = Time.mktime(1973, "jan", 18, 3, 45, 50)
-print "In localtime it gives: ", time.localtime, "\n"
-
-
-# @@PLEAC@@_3.9
-# Ruby provides micro-seconds in Time object
-Time.now.usec
-
-# Ruby gives the seconds in floating format when substracting two Time objects
-before = Time.now
-line = gets
-elapsed = Time.now - before
-puts "You took #{elapsed} seconds."
-
-# On my Celeron-400 with Linux-2.2.19-14mdk, average for three execs are:
-# This Ruby version: average 0.00321 sec
-# Cookbook's Perl version: average 0.00981 sec
-size = 500
-number_of_times = 100
-total_time = 0
-number_of_times.times {
- # populate array
- array = []
- size.times { array << rand }
- # sort it
- begin_ = Time.now
- array.sort!
- time = Time.now - begin_
- total_time += time
-}
-printf "On average, sorting %d random numbers takes %.5f seconds\n",
- size, (total_time/Float(number_of_times))
-
-
-# @@PLEAC@@_3.10
-sleep(0.005) # Ruby is definitely not as broken as Perl :)
-# (may be interrupted by sending the process a SIGALRM)
-
-
-# @@PLEAC@@_3.11
-#!/usr/bin/ruby -w
-# hopdelta - feed mail header, produce lines
-# showing delay at each hop.
-require 'time'
-class MailHopDelta
-
- def initialize(mail)
- @head = mail.gsub(/\n\s+/,' ')
- @topline = %w-Sender Recipient Time Delta-
- @start_from = mail.match(/^From.*\@([^\s>]*)/)[1]
- @date = Time.parse(mail.match(/^Date:\s+(.*)/)[1])
- end
-
- def out(line)
- "%-20.20s %-20.20s %-20.20s %s" % line
- end
-
- def hop_date(day)
- day.strftime("%I:%M:%S %Y/%m/%d")
- end
-
- def puts_hops
- puts out(@topline)
- puts out(['Start', @start_from, hop_date(@date),''])
- @head.split(/\n/).reverse.grep(/^Received:/).each do |hop|
- hop.gsub!(/\bon (.*?) (id.*)/,'; \1')
- whence = hop.match(/;\s+(.*)$/)[1]
- unless whence
- warn "Bad received line: #{hop}"
- next
- end
- from = $+ if hop =~ /from\s+(\S+)|\((.*?)\)/
- by = $1 if hop =~ /by\s+(\S+\.\S+)/
- next unless now = Time.parse(whence).localtime
- delta = now - @date
- puts out([from, by, hop_date(now), hop_time(delta)])
- @date = now
- end
- end
-
- def hop_time(secs)
- sign = secs < 0 ? -1 : 1
- days, secs = secs.abs.divmod(60 * 60 * 24)
- hours,secs = secs.abs.divmod(60 * 60)
- mins, secs = secs.abs.divmod(60)
- rtn = "%3ds" % [secs * sign]
- rtn << "%3dm" % [mins * sign] if mins != 0
- rtn << "%3dh" % [hours * sign] if hours != 0
- rtn << "%3dd" % [days * sign] if days != 0
- rtn
- end
-end
-
-$/ = ""
-mail = MailHopDelta.new(ARGF.gets).puts_hops
-
-
-# @@PLEAC@@_4.0
-single_level = [ "this", "that", "the", "other" ]
-
-# Ruby directly supports nested arrays
-double_level = [ "this", "that", [ "the", "other" ] ]
-still_single_level = [ "this", "that", [ "the", "other" ] ].flatten
-
-
-# @@PLEAC@@_4.1
-a = [ "quick", "brown", "fox" ]
-a = %w(Why are you teasing me?)
-
-lines = <<"END_OF_HERE_DOC".gsub(/^\s*(.+)/, '\1')
- The boy stood on the burning deck,
- It was as hot as glass.
-END_OF_HERE_DOC
-
-bigarray = IO.readlines("mydatafile").collect { |l| l.chomp }
-
-name = "Gandalf"
-banner = %Q(Speak, #{name}, and welcome!)
-
-host_info = `host #{his_host}`
-
-%x(ps #{$$})
-
-banner = 'Costs only $4.95'.split(' ')
-
-rax = %w! ( ) < > { } [ ] !
-
-
-# @@PLEAC@@_4.2
-def commify_series(a)
- a.size == 0 ? '' :
- a.size == 1 ? a[0] :
- a.size == 2 ? a.join(' and ') :
- a[0..-2].join(', ') + ', and ' + a[-1]
-end
-
-array = [ "red", "yellow", "green" ]
-
-print "I have ", array, " marbles\n"
-# -> I have redyellowgreen marbles
-
-# But unlike Perl:
-print "I have #{array} marbles\n"
-# -> I have redyellowgreen marbles
-# So, needs:
-print "I have #{array.join(' ')} marbles\n"
-# -> I have red yellow green marbles
-
-def commify_series(a)
- sepchar = a.select { |p| p =~ /,/ } != [] ? '; ' : ', '
- a.size == 0 ? '' :
- a.size == 1 ? a[0] :
- a.size == 2 ? a.join(' and ') :
- a[0..-2].join(sepchar) + sepchar + 'and ' + a[-1]
-end
-
-
-# @@PLEAC@@_4.3
-# (note: AFAIK Ruby doesn't allow gory change of Array length)
-# grow the array by assigning nil to past the end of array
-ary[new_size-1] = nil
-# shrink the array by slicing it down
-ary.slice!(new_size..-1)
-# init the array with given size
-Array.new(number_of_elems)
-# assign to an element past the original end enlarges the array
-ary[index_new_last_elem] = value
-
-def what_about_that_array(a)
- print "The array now has ", a.size, " elements.\n"
- # Index of last element is not really interesting in Ruby
- print "Element #3 is `#{a[3]}'.\n"
-end
-people = %w(Crosby Stills Nash Young)
-what_about_that_array(people)
-
-
-# @@PLEAC@@_4.4
-# OO style
-bad_users.each { |user|
- complain(user)
-}
-# or, functional style
-for user in bad_users
- complain(user)
-end
-
-for var in ENV.keys.sort
- puts "#{var}=#{ENV[var]}"
-end
-
-for user in all_users
- disk_space = get_usage(user)
- if (disk_space > MAX_QUOTA)
- complain(user)
- end
-end
-
-for l in IO.popen("who").readlines
- print l if l =~ /^gc/
-end
-
-# we can mimic the obfuscated Perl way
-while fh.gets # $_ is set to the line just read
- chomp # $_ has a trailing \n removed, if it had one
- split.each { |w| # $_ is split on whitespace
- # but $_ is not set to each chunk as in Perl
- print w.reverse
- }
-end
-# ...or use a cleaner way
-for l in fh.readlines
- l.chomp.split.each { |w| print w.reverse }
-end
-
-# same drawback as in problem 1.4, we can't mutate a Numeric...
-array.collect! { |v| v - 1 }
-
-a = [ .5, 3 ]; b = [ 0, 1 ]
-for ary in [ a, b ]
- ary.collect! { |v| v * 7 }
-end
-puts "#{a.join(' ')} #{b.join(' ')}"
-
-# we can mutate Strings, cool; we need a trick for the scalar
-for ary in [ [ scalar ], array, hash.values ]
- ary.each { |v| v.strip! } # String#strip rules :)
-end
-
-
-# @@PLEAC@@_4.5
-# not relevant in Ruby since we have always references
-for item in array
- # do somethingh with item
-end
-
-
-# @@PLEAC@@_4.6
-unique = list.uniq
-
-# generate a list of users logged in, removing duplicates
-users = `who`.collect { |l| l =~ /(\w+)/; $1 }.sort.uniq
-puts("users logged in: #{commify_series(users)}") # see 4.2 for commify_series
-
-
-# @@PLEAC@@_4.7
-a - b
-# [ 1, 1, 2, 2, 3, 3, 3, 4, 5 ] - [ 1, 2, 4 ] -> [3, 5]
-
-
-# @@PLEAC@@_4.8
-union = a | b
-intersection = a & b
-difference = a - b
-
-
-# @@PLEAC@@_4.9
-array1.concat(array2)
-# if you will assign to another object, better use:
-new_ary = array1 + array2
-
-members = [ "Time", "Flies" ]
-initiates = [ "An", "Arrow" ]
-members += initiates
-
-members = [ "Time", "Flies" ]
-initiates = [ "An", "Arrow" ]
-members[2,0] = [ "Like", initiates ].flatten
-
-members[0] = "Fruit"
-members[3,2] = "A", "Banana"
-
-
-# @@PLEAC@@_4.10
-reversed = ary.reverse
-
-ary.reverse_each { |e|
- # do something with e
-}
-
-descending = ary.sort.reverse
-descending = ary.sort { |a,b| b <=> a }
-
-
-# @@PLEAC@@_4.11
-# remove n elements from front of ary (shift n)
-front = ary.slice!(0, n)
-
-# remove n elements from the end of ary (pop n)
-end_ = ary.slice!(-n .. -1)
-
-# let's extend the Array class, to make that useful
-class Array
- def shift2()
- slice!(0 .. 1) # more symetric with pop2...
- end
- def pop2()
- slice!(-2 .. -1)
- end
-end
-
-friends = %w(Peter Paul Mary Jim Tim)
-this, that = friends.shift2
-
-beverages = %w(Dew Jolt Cola Sprite Fresca)
-pair = beverages.pop2
-
-
-# @@PLEAC@@_4.12
-# use Enumerable#detect (or the synonym Enumerable#find)
-highest_eng = employees.detect { |emp| emp.category == 'engineer' }
-
-
-# @@PLEAC@@_4.13
-# use Enumerable#select (or the synonym Enumerable#find_all)
-bigs = nums.select { |i| i > 1_000_000 }
-pigs = users.keys.select { |k| users[k] > 1e7 }
-
-matching = `who`.select { |u| u =~ /^gnat / }
-
-engineers = employees.select { |e| e.position == 'Engineer' }
-
-secondary_assistance = applicants.select { |a|
- a.income >= 26_000 && a.income < 30_000
-}
-
-
-# @@PLEAC@@_4.14
-# normally you would have an array of Numeric (Float or
-# Fixnum or Bignum), so you would use:
-sorted = unsorted.sort
-# if you have strings representing Integers or Floats
-# you may specify another sort method:
-sorted = unsorted.sort { |a,b| a.to_f <=> b.to_f }
-
-# let's use the list of my own PID's
-`ps ux`.split("\n")[1..-1].
- select { |i| i =~ /^#{ENV['USER']}/ }.
- collect { |i| i.split[1] }.
- sort { |a,b| a.to_i <=> b.to_i }.each { |i| puts i }
-puts "Select a process ID to kill:"
-pid = gets.chomp
-raise "Exiting ... \n" unless pid && pid =~ /^\d+$/
-Process.kill('TERM', pid.to_i)
-sleep 2
-Process.kill('KILL', pid.to_i)
-
-descending = unsorted.sort { |a,b| b.to_f <=> a.to_f }
-
-
-# @@PLEAC@@_4.15
-ordered = unordered.sort { |a,b| compare(a,b) }
-
-precomputed = unordered.collect { |e| [compute, e] }
-ordered_precomputed = precomputed.sort { |a,b| a[0] <=> b[0] }
-ordered = ordered_precomputed.collect { |e| e[1] }
-
-ordered = unordered.collect { |e| [compute, e] }.
- sort { |a,b| a[0] <=> b[0] }.
- collect { |e| e[1] }
-
-for employee in employees.sort { |a,b| a.name <=> b.name }
- print employee.name, " earns \$ ", employee.salary, "\n"
-end
-
-# Beware! `0' is true in Ruby.
-# For chaining comparisons, you may use Numeric#nonzero?, which
-# returns num if num is not zero, nil otherwise
-sorted = employees.sort { |a,b| (a.name <=> b.name).nonzero? || b.age <=> a.age }
-
-users = []
-# getpwent is not wrapped in Ruby... let's fallback
-IO.readlines('/etc/passwd').each { |u| users << u.split(':') }
-users.sort! { |a,b| a[0] <=> b[0] }
-for user in users
- puts user[0]
-end
-
-sorted = names.sort { |a,b| a[1, 1] <=> b[1, 1] }
-sorted = strings.sort { |a,b| a.length <=> b.length }
-
-# let's show only the compact version
-ordered = strings.collect { |e| [e.length, e] }.
- sort { |a,b| a[0] <=> b[0] }.
- collect { |e| e[1] }
-
-ordered = strings.collect { |e| [/\d+/.match(e)[0].to_i, e] }.
- sort { |a,b| a[0] <=> b[0] }.
- collect { |e| e[1] }
-
-print `cat /etc/passwd`.collect { |e| [e, e.split(':').indexes(3,2,0)].flatten }.
- sort { |a,b| (a[1] <=> b[1]).nonzero? || (a[2] <=> b[2]).nonzero? || a[3] <=> b[3] }.
- collect { |e| e[0] }
-
-
-# @@PLEAC@@_4.16
-circular.unshift(circular.pop) # the last shall be first
-circular.push(circular.shift) # and vice versa
-
-def grab_and_rotate(l)
- l.push(ret = l.shift)
- ret
-end
-
-processes = [1, 2, 3, 4, 5]
-while (1)
- process = grab_and_rotate(processes)
- puts "Handling process #{process}"
- sleep 1
-end
-
-
-# @@PLEAC@@_4.17
-def fisher_yates_shuffle(a)
- (a.size-1).downto(1) { |i|
- j = rand(i+1)
- a[i], a[j] = a[j], a[i] if i != j
- }
-end
-
-def naive_shuffle(a)
- for i in 0...a.size
- j = rand(a.size)
- a[i], a[j] = a[j], a[i]
- end
-end
-
-
-# @@PLEAC@@_4.18
-#!/usr/bin/env ruby
-# example 4-2 words
-# words - gather lines, present in colums
-
-# class to encapsulate the word formatting from the input
-class WordFormatter
- def initialize(cols)
- @cols = cols
- end
-
- # helper to return the length of the longest word in the wordlist
- def maxlen(wordlist)
- max = 1
- for word in wordlist
- if word.length > max
- max = word.length
- end
- end
- max
- end
-
- # process the wordlist and print it formmated into columns
- def output(wordlist)
- collen = maxlen(wordlist) + 1
- columns = @cols / collen
- columns = 1 if columns == 0
- rows = (wordlist.length + columns - 1) / columns
- # now process each item, picking out proper piece for this position
- 0.upto(rows * columns - 1) { |item|
- target = (item % columns) * rows + (item / columns)
- eol = ((item+1) % columns == 0)
- piece = wordlist[target] || ""
- piece = piece.ljust(collen) unless eol
- print piece
- puts if eol
- }
- # no need to finish it up, because eol is always true for the last element
- end
-end
-
-# get nr of chars that fit in window or console, see PLEAC 15.4
-# not portable -- linux only (?)
-def getWinCharWidth()
- buf = "\0" * 8
- $stdout.ioctl(0x5413, buf)
- ws_row, ws_col, ws_xpixel, ws_ypixel = buf.unpack("$4")
- ws_col || 80
-rescue
- 80
-end
-
-# main program
-cols = getWinCharWidth()
-formatter = WordFormatter.new(cols)
-words = readlines()
-words.collect! { |line|
- line.chomp
-}
-formatter.output(words)
-
-
-# @@PLEAC@@_4.19
-# In ruby, Fixnum's are automatically converted to Bignum's when
-# needed, so there is no need for an extra module
-def factorial(n)
- s = 1
- while n > 0
- s *= n
- n -= 1
- end
- s
-end
-
-puts factorial(500)
-
-#---------------------------------------------------------
-# Example 4-3. tsc-permute
-# tsc_permute: permute each word of input
-def permute(items, perms)
- unless items.length > 0
- puts perms.join(" ")
- else
- for i in items
- newitems = items.dup
- newperms = perms.dup
- newperms.unshift(newitems.delete(i))
- permute(newitems, newperms)
- end
- end
-end
-# In ruby the main program must be after all definitions it is using
-permute(ARGV, [])
-
-#---------------------------------------------------------
-# mjd_permute: permute each word of input
-
-def factorial(n)
- s = 1
- while n > 0
- s *= n
- n -= 1
- end
- s
-end
-
-# we use a class with a class variable store the private cache
-# for the results of the factorial function.
-class Factorial
- @@fact = [ 1 ]
- def Factorial.compute(n)
- if @@fact[n]
- @@fact[n]
- else
- @@fact[n] = n * Factorial.compute(n - 1)
- end
- end
-end
-
-#---------------------------------------------------------
-# Example 4-4- mjd-permute
-# n2pat(n, len): produce the N-th pattern of length len
-
-# We must use a lower case letter as parameter N, otherwise it is
-# handled as constant Length is the length of the resulting
-# array, not the index of the last element (length -1) like in
-# the perl example.
-def n2pat(n, length)
- pat = []
- i = 1
- while i <= length
- pat.push(n % i)
- n /= i
- i += 1
- end
- pat
-end
-
-# pat2perm(pat): turn pattern returned by n2pat() into
-# permutation of integers.
-def pat2perm(pat)
- source = (0 .. pat.length - 1).to_a
- perm = []
- perm.push(source.slice!(pat.pop)) while pat.length > 0
- perm
-end
-
-def n2perm(n, len)
- pat2perm(n2pat(n,len))
-end
-
-# In ruby the main program must be after all definitions
-while gets
- data = split
- # the perl solution has used $#data, which is length-1
- num_permutations = Factorial.compute(data.length())
- 0.upto(num_permutations - 1) do |i|
- # in ruby we can not use an array as selector for an array
- # but by exchanging the two arrays, we can use the collect method
- # which returns an array with the result of all block invocations
- permutation = n2perm(i, data.length).collect {
- |j| data[j]
- }
- puts permutation.join(" ")
- end
-end
-
-
-# @@PLEAC@@_5.0
-age = { "Nat", 24,
- "Jules", 25,
- "Josh", 17 }
-
-age["Nat"] = 24
-age["Jules"] = 25
-age["Josh"] = 17
-
-food_color = {
- "Apple" => "red",
- "Banana" => "yellow",
- "Lemon" => "yellow",
- "Carrot" => "orange"
- }
-
-# In Ruby, you cannot avoid the double or simple quoting
-# while manipulatin hashes
-
-
-# @@PLEAC@@_5.1
-hash[key] = value
-
-food_color["Raspberry"] = "pink"
-puts "Known foods:", food_color.keys
-
-
-# @@PLEAC@@_5.2
-# does hash have a value for key ?
-if (hash.has_key?(key))
- # it exists
-else
- # it doesn't
-end
-
-[ "Banana", "Martini" ].each { |name|
- print name, " is a ", food_color.has_key?(name) ? "food" : "drink", "\n"
-}
-
-age = {}
-age['Toddler'] = 3
-age['Unborn'] = 0
-age['Phantasm'] = nil
-
-for thing in ['Toddler', 'Unborn', 'Phantasm', 'Relic']
- print "#{thing}: "
- print "Has-key " if age.has_key?(thing)
- print "True " if age[thing]
- print "Nonzero " if age[thing] && age[thing].nonzero?
- print "\n"
-end
-
-#=>
-# Toddler: Has-key True Nonzero
-# Unborn: Has-key True
-# Phantasm: Has-key
-# Relic:
-
-# You use Hash#has_key? when you use Perl's exists -> it checks
-# for existence of a key in a hash.
-# All Numeric are "True" in ruby, so the test doesn't have the
-# same semantics as in Perl; you would use Numeric#nonzero? to
-# achieve the same semantics (false if 0, true otherwise).
-
-
-# @@PLEAC@@_5.3
-food_color.delete("Banana")
-
-
-# @@PLEAC@@_5.4
-hash.each { |key, value|
- # do something with key and value
-}
-
-hash.each_key { |key|
- # do something with key
-}
-
-food_color.each { |food, color|
- puts "#{food} is #{color}"
-}
-
-food_color.each_key { |food|
- puts "#{food} is #{food_color[food]}"
-}
-
-# IMO this demonstrates that OO style is by far more readable
-food_color.keys.sort.each { |food|
- puts "#{food} is #{food_color[food]}."
-}
-
-#-----------------------------
-#!/usr/bin/ruby
-# countfrom - count number of messages from each sender
-
-# Default value is 0
-from = Hash.new(0)
-while gets
- /^From: (.*)/ and from[$1] += 1
-end
-
-# More useful to sort by number of received mail by person
-from.sort {|a,b| b[1]<=>a[1]}.each { |v|
- puts "#{v[1]}: #{v[0]}"
-}
-#-----------------------------
-
-
-# @@PLEAC@@_5.5
-# You may use the built-in 'inspect' method this way:
-p hash
-
-# Or do it the Cookbook way:
-hash.each { |k,v| puts "#{k} => #{v}" }
-
-# Sorted by keys
-hash.sort.each { |e| puts "#{e[0]} => #{e[1]}" }
-# Sorted by values
-hash.sort{|a,b| a[1]<=>b[1]}.each { |e| puts "#{e[0]} => #{e[1]}" }
-
-
-# @@PLEAC@@_5.7
-ttys = Hash.new
-for i in `who`
- user, tty = i.split
- (ttys[user] ||= []) << tty # see problems_ruby for more infos
-end
-ttys.keys.sort.each { |k|
- puts "#{k}: #{commify_series(ttys[k])}" # from 4.2
-}
-
-
-# @@PLEAC@@_5.8
-surname = { "Mickey" => "Mantle", "Babe" => "Ruth" }
-puts surname.index("Mantle")
-
-# If you really needed to 'invert' the whole hash, use Hash#invert
-
-#-----------------------------
-#!/usr/bin/ruby -w
-# foodfind - find match for food or color
-
-given = ARGV.shift or raise "usage: foodfind food_or_color"
-
-color = {
- "Apple" => "red",
- "Banana" => "yellow",
- "Lemon" => "yellow",
- "Carrot" => "orange",
-}
-
-if (color.has_key?(given))
- puts "#{given} is a food with color #{color[given]}."
-end
-if (color.has_value?(given))
- puts "#{color.index(given)} is a food with color #{given}."
-end
-#-----------------------------
-
-
-# @@PLEAC@@_5.9
-# Sorted by keys (Hash#sort gives an Array of pairs made of each key,value)
-food_color.sort.each { |f|
- puts "#{f[0]} is #{f[1]}."
-}
-
-# Sorted by values
-food_color.sort { |a,b| a[1] <=> b[1] }.each { |f|
- puts "#{f[0]} is #{f[1]}."
-}
-
-# Sorted by length of values
-food_color.sort { |a,b| a[1].length <=> b[1].length }.each { |f|
- puts "#{f[0]} is #{f[1]}."
-}
-
-
-# @@PLEAC@@_5.10
-merged = a.clone.update(b) # because Hash#update changes object in place
-
-drink_color = { "Galliano" => "yellow", "Mai Tai" => "blue" }
-ingested_color = drink_color.clone.update(food_color)
-
-substance_color = {}
-for i in [ food_color, drink_color ]
- i.each_key { |k|
- if substance_color.has_key?(k)
- puts "Warning: #{k} seen twice. Using the first definition."
- next
- end
- substance_color[k] = 1
- }
-end
-
-
-# @@PLEAC@@_5.11
-common = hash1.keys & hash2.keys
-
-this_not_that = hash1.keys - hash2.keys
-
-
-# @@PLEAC@@_5.12
-# no problem here, Ruby handles any kind of object for key-ing
-# (it takes Object#hash, which defaults to Object#id)
-
-
-# @@PLEAC@@_5.13
-# AFAIK, not possible in Ruby
-
-
-# @@PLEAC@@_5.14
-# Be careful, the following is possible only because Fixnum objects are
-# special (documentation says: there is effectively only one Fixnum object
-# instance for any given integer value).
-count = Hash.new(0)
-array.each { |e|
- count[e] += 1
-}
-
-
-# @@PLEAC@@_5.15
-father = {
- "Cain" , "Adam",
- "Abel" , "Adam",
- "Seth" , "Adam",
- "Enoch" , "Cain",
- "Irad" , "Enoch",
- "Mehujael" , "Irad",
- "Methusael" , "Mehujael",
- "Lamech" , "Methusael",
- "Jabal" , "Lamech",
- "Jubal" , "Lamech",
- "Tubalcain" , "Lamech",
- "Enos" , "Seth",
-}
-
-while gets
- chomp
- begin
- print $_, " "
- end while $_ = father[$_]
- puts
-end
-
-children = {}
-father.each { |k,v|
- (children[v] ||= []) << k
-}
-while gets
- chomp
- puts "#{$_} begat #{(children[$_] || ['Nobody']).join(', ')}.\n"
-end
-
-includes = {}
-files.each { |f|
- begin
- for l in IO.readlines(f)
- next unless l =~ /^\s*#\s*include\s*<([^>]+)>/
- (includes[$1] ||= []) << f
- end
- rescue SystemCallError
- $stderr.puts "#$! (skipping)"
- end
-}
-
-include_free = includes.values.flatten.uniq - includes.keys
-
-
-# @@PLEAC@@_5.16
-# dutree - print sorted intented rendition of du output
-#% dutree
-#% dutree /usr
-#% dutree -a
-#% dutree -a /bin
-
-# The DuNode class collects all information about a directory,
-# and provides some convenience methods
-class DuNode
-
- attr_reader :name
- attr_accessor :size
- attr_accessor :kids
-
- def initialize(name)
- @name = name
- @kids = []
- @size = 0
- end
-
- # support for sorting nodes with side
- def size_compare(node2)
- @size <=> node2.size
- end
-
- def basename
- @name.sub(/.*\//, "")
- end
-
- #returns substring before last "/", nil if not there
- def parent
- p = @name.sub(/\/[^\/]+$/,"")
- if p == @name
- nil
- else
- p
- end
- end
-
-end
-
-# The DuTree does the acdtual work of
-# getting the input, parsing it, builging up a tree
-# and format it for output
-class Dutree
-
- attr_reader :topdir
-
- def initialize
- @nodes = Hash.new
- @dirsizes = Hash.new(0)
- @kids = Hash.new([])
- end
-
- # get a node by name, create it if it does not exist yet
- def get_create_node(name)
- if @nodes.has_key?(name)
- @nodes[name]
- else
- node = DuNode.new(name)
- @nodes[name] = node
- node
- end
- end
-
- # run du, read in input, save sizes and kids
- # stores last directory read in instance variable topdir
- def input(arguments)
- name = ""
- cmd = "du " + arguments.join(" ")
- IO.popen(cmd) { |pipe|
- pipe.each { |line|
- size, name = line.chomp.split(/\s+/, 2)
- node = get_create_node(name)
- node.size = size.to_i
- @nodes[name] = node
- parent = node.parent
- if parent
- get_create_node(parent).kids.push(node)
- end
- }
- }
- @topdir = @nodes[name]
- end
-
- # figure out how much is taken in each directory
- # that isn't stored in the subdirectories. Add a new
- # fake kid called "." containing that much.
- def get_dots(node)
- cursize = node.size
- for kid in node.kids
- cursize -= kid.size
- get_dots(kid)
- end
- if node.size != cursize
- newnode = get_create_node(node.name + "/.")
- newnode.size = cursize
- node.kids.push(newnode)
- end
- end
-
- # recursively output everything
- # passing padding and number width as well
- # on recursive calls
- def output(node, prefix="", width=0)
- line = sprintf("%#{width}d %s", node.size, node.basename)
- puts(prefix + line)
- prefix += line.sub(/\d /, "| ")
- prefix.gsub!(/[^|]/, " ")
- if node.kids.length > 0 # not a bachelor node
- kids = node.kids
- kids.sort! { |a,b|
- b.size_compare(a)
- }
- width = kids[0].size.to_s.length
- for kid in kids
- output(kid, prefix, width)
- end
- end
- end
-
-end
-
-tree = Dutree.new
-tree.input(ARGV)
-tree.get_dots(tree.topdir)
-tree.output(tree.topdir)
-
-
-# @@PLEAC@@_6.0
-# The verbose version are match, sub, gsub, sub! and gsub!;
-# pattern needs to be a Regexp object; it yields a MatchData
-# object.
-pattern.match(string)
-string.sub(pattern, replacement)
-string.gsub(pattern, replacement)
-# As usual in Ruby, sub! does the same as sub but also modifies
-# the object, the same for gsub!/gsub.
-
-# Sugared syntax yields the position of the match (or nil if no
-# match). Note that the object at the right of the operator needs
-# not to be a Regexp object (it can be a String). The "dont
-# match" operator yields true or false.
-meadow =~ /sheep/ # position of the match, nil if no match
-meadow !~ /sheep/ # true if doesn't match, false if it does
-# There is no sugared version for the substitution
-
-meadow =~ /\bovines?\b/i and print "Here be sheep!"
-
-string = "good food"
-string.sub!(/o*/, 'e')
-
-# % echo ababacaca | ruby -ne 'puts $& if /(a|ba|b)+(a|ac)+/'
-# ababa
-
-# The "global" (or "multiple") match is handled by String#scan
-scan (/(\d+)/) {
- puts "Found number #{$1}"
-}
-
-# String#scan yields an Array if not used with a block
-numbers = scan(/\d+/)
-
-digits = "123456789"
-nonlap = digits.scan(/(\d\d\d)/)
-yeslap = digits.scan(/(?=(\d\d\d))/)
-puts "Non-overlapping: #{nonlap.join(' ')}"
-puts "Overlapping: #{yeslap.join(' ')}";
-# Non-overlapping: 123 456 789
-# Overlapping: 123 234 345 456 567 678 789
-
-string = "And little lambs eat ivy"
-string =~ /l[^s]*s/
-puts "(#$`) (#$&) (#$')"
-# (And ) (little lambs) ( eat ivy)
-
-
-# @@PLEAC@@_6.1
-# Ruby doesn't have the same problem:
-dst = src.sub('this', 'that')
-
-progname = $0.sub('^.*/', '')
-
-bindirs = %w(/usr/bin /bin /usr/local/bin)
-libdirs = bindirs.map { |l| l.sub('bin', 'lib') }
-
-
-# @@PLEAC@@_6.3
-/\S+/ # as many non-whitespace bytes as possible
-/[A-Za-z'-]+/ # as many letters, apostrophes, and hyphens
-
-/\b([A-Za-z]+)\b/ # usually best
-/\s([A-Za-z]+)\s/ # fails at ends or w/ punctuation
-
-
-# @@PLEAC@@_6.4
-require 'socket'
-str = 'www.ruby-lang.org and www.rubygarden.org'
-re = /
- ( # capture the hostname in $1
- (?: # these parens for grouping only
- (?! [-_] ) # lookahead for neither underscore nor dash
- [\w-] + # hostname component
- \. # and the domain dot
- ) + # now repeat that whole thing a bunch of times
- [A-Za-z] # next must be a letter
- [\w-] + # now trailing domain part
- ) # end of $1 capture
- /x # /x for nice formatting
-
-str.gsub! re do # pass a block to execute replacement
- host = TCPsocket.gethostbyname($1)
- "#{$1} [#{host[3]}]"
-end
-
-puts str
-#-----------------------------
-# to match whitespace or #-characters in an extended re you need to escape
-# them.
-
-foo = 42
-str = 'blah #foo# blah'
-str.gsub! %r/ # replace
- \# # a pound sign
- (\w+) # the variable name
- \# # another pound sign
- /x do
- eval $1 # with the value of a local variable
- end
-puts str # => blah 42 blah
-
-
-# @@PLEAC@@_6.5
-# The 'g' modifier doesn't exist in Ruby, a regexp can't be used
-# directly in a while loop; instead, use String#scan { |match| .. }
-fish = 'One fish two fish red fish blue fish'
-WANT = 3
-count = 0
-fish.scan(/(\w+)\s+fish\b/i) {
- if (count += 1) == WANT
- puts "The third fish is a #{$1} one."
- end
-}
-
-if fish =~ /(?:\w+\s+fish\s+){2}(\w+)\s+fish/i
- puts "The third fish is a #{$1} one."
-end
-
-pond = 'One fish two fish red fish blue fish'
-# String#scan without a block gives an array of matches, each match
-# being an array of all the specified groups
-colors = pond.scan(/(\w+)\s+fish\b/i).flatten # get all matches
-color = colors[2] # then the one we want
-# or without a temporary array
-color = pond.scan(/(\w+)\s+fish\b/i).flatten[2] # just grab element 3
-puts "The third fish in the pond is #{color}."
-
-count = 0
-fishes = 'One fish two fish red fish blue fish'
-evens = fishes.scan(/(\w+)\s+fish\b/i).select { (count+=1) % 2 == 0 }
-print "Even numbered fish are #{evens.join(' ')}."
-
-count = 0
-fishes.gsub(/
- \b # makes next \w more efficient
- ( \w+ ) # this is what we\'ll be changing
- (
- \s+ fish \b
- )
- /x) {
- if (count += 1) == 4
- 'sushi' + $2
- else
- $1 + $2
- end
-}
-
-pond = 'One fish two fish red fish blue fish swim here.'
-puts "Last fish is #{pond.scan(/\b(\w+)\s+fish\b/i).flatten[-1]}"
-
-/
- A # find some pattern A
- (?! # mustn\'t be able to find
- .* # something
- A # and A
- )
- $ # through the end of the string
-/x
-
-# The "s" perl modifier is "m" in Ruby (not very nice since there is
-# also an "m" in perl..)
-pond = "One fish two fish red fish blue fish swim here."
-if (pond =~ /
- \b ( \w+) \s+ fish \b
- (?! .* \b fish \b )
- /mix)
- puts "Last fish is #{$1}."
-else
- puts "Failed!"
-end
-
-
-# @@PLEAC@@_6.6
-#-----------------------------
-#!/usr/bin/ruby -w
-# killtags - very bad html killer
-$/ = nil; # each read is whole file
-while file = gets() do
- file.gsub!(/<.*?>/m,''); # strip tags (terribly)
- puts file # print file to STDOUT
-end
-#-----------------------------
-#!/usr/bin/ruby -w
-#headerfy - change certain chapter headers to html
-$/ = ''
-while file = gets() do
- pattern = /
- \A # start of record
- ( # capture in $1
- Chapter # text string
- \s+ # mandatory whitespace
- \d+ # decimal number
- \s* # optional whitespace
- : # a real colon
- . * # anything not a newline till end of line
- )
- /x
- puts file.gsub(pattern,'<H1>\1</H1>')
-end
-#-----------------------------
-#% ruby -00pe "gsub!(/\A(Chapter\s+\d+\s*:.*)/,'<H1>\1</H1>')" datafile
-
-#!/usr/bin/ruby -w
-#-----------------------------
-for file in ARGV
- file = File.open(ARGV.shift)
- while file.gets('') do # each read is a paragraph
- print "chunk #{$.} in $ARGV has <<#{$1}>>\n" while /^START(.*?)^END/m
- end # /m activates the multiline mode
-end
-#-----------------------------
-
-# @@PLEAC@@_6.7
-#-----------------------------
-$/ = nil;
-file = File.open("datafile")
-chunks = file.gets.split(/pattern/)
-#-----------------------------
-# .Ch, .Se and .Ss divide chunks of STDIN
-chunks = gets(nil).split(/^\.(Ch|Se|Ss)$/)
-print "I read #{chunks.size} chunks.\n"
-#-----------------------------
-
-
-# @@PLEAC@@_6.8
-while gets
- if ~/BEGIN/ .. ~/END/
- # line falls between BEGIN and END inclusive
- end
-end
-
-while gets
- if ($. == firstnum) .. ($. == lastnum)
- # operate between firstnum and lastnum line number
- end
-end
-
-# in ruby versions prior to 1.8, the above two conditional
-# expressions could be shortened to:
-# if /BEGIN/ .. /END/
-# and
-# if firstnum .. lastnum
-# but these now only work this way from the command line
-
-#-----------------------------
-
-while gets
- if ~/BEGIN/ ... ~/END/
- # line falls between BEGIN and END on different lines
- end
-end
-
-while gets
- if ($. == first) ... ($. == last)
- # operate between first and last line number on different lines
- end
-end
-
-#-----------------------------
-# command-line to print lines 15 through 17 inclusive (see below)
-ruby -ne 'print if 15 .. 17' datafile
-
-# print out all <XMP> .. </XMP> displays from HTML doc
-while gets
- print if ~%r#<XMP>#i .. ~%r#</XMP>#i;
-end
-
-# same, but as shell command
-# ruby -ne 'print if %r#<XMP>#i .. %r#</XMP>#i' document.html
-#-----------------------------
-# ruby -ne 'BEGIN { $top=3; $bottom=5 }; \
-# print if $top .. $bottom' /etc/passwd # FAILS
-# ruby -ne 'BEGIN { $top=3; $bottom=5 }; \
-# print if $. == $top .. $. == $bottom' /etc/passwd # works
-# ruby -ne 'print if 3 .. 5' /etc/passwd # also works
-#-----------------------------
-print if ~/begin/ .. ~/end/;
-print if ~/begin/ ... ~/end/;
-#-----------------------------
-while gets
- $in_header = $. == 1 .. ~/^$/ ? true : false
- $in_body = ~/^$/ .. ARGF.eof ? true : false
-end
-#-----------------------------
-seen = {}
-ARGF.each do |line|
- next unless line =~ /^From:?\s/i .. line =~ /^$/;
- line.scan(%r/([^<>(),;\s]+\@[^<>(),;\s]+)/).each do |addr|
- puts addr unless seen[addr]
- seen[addr] ||= 1
- end
-end
-
-
-# @@PLEAC@@_6.9
-def glob2pat(globstr)
- patmap = {
- '*' => '.*',
- '?' => '.',
- '[' => '[',
- ']' => ']',
- }
- globstr.gsub!(/(.)/) { |c| patmap[c] || Regexp::escape(c) }
- '^' + globstr + '$'
-end
-
-
-# @@PLEAC@@_6.10
-# avoid interpolating patterns like this if the pattern
-# isn't going to change:
-pattern = ARGV.shift
-ARGF.each do |line|
- print line if line =~ /#{pattern}/
-end
-
-# the above creates a new regex each iteration. Instead,
-# use the /o modifier so the regex is compiled only once
-
-pattern = ARGV.shift
-ARGF.each do |line|
- print line if line =~ /#{pattern}/o
-end
-
-#-----------------------------
-
-#!/usr/bin/ruby
-# popgrep1 - grep for abbreviations of places that say "pop"
-# version 1: slow but obvious way
-popstates = %w(CO ON MI WI MN)
-ARGF.each do |line|
- popstates.each do |state|
- if line =~ /\b#{state}\b/
- print line
- last
- end
- end
-end
-
-#-----------------------------
-#!/usr/bin/ruby
-# popgrep2 - grep for abbreviations of places that say "pop"
-# version 2: eval strings; fast but hard to quote
-popstates = %w(CO ON MI WI MN)
-code = "ARGF.each do |line|\n"
-popstates.each do |state|
- code += "\tif line =~ /\\b#{state}\\b/; print(line); next; end\n"
-end
-code += "end\n"
-print "CODE IS\n---\n#{code}\n---\n" if false # turn on for debugging
-eval code
-
-# CODE IS
-# ---
-# ARGF.each do |line|
-# if line =~ /\bCO\b/; print(line); next; end
-# if line =~ /\bON\b/; print(line); next; end
-# if line =~ /\bMI\b/; print(line); next; end
-# if line =~ /\bWI\b/; print(line); next; end
-# if line =~ /\bMN\b/; print(line); next; end
-# end
-#
-# ---
-
-## alternatively, the same idea as above but compiling
-## to a case statement: (not in perlcookbook)
-#!/usr/bin/ruby -w
-# popgrep2.5 - grep for abbreviations of places that say "pop"
-# version 2.5: eval strings; fast but hard to quote
-popstates = %w(CO ON MI WI MN)
-code = "ARGF.each do |line|\n case line\n"
-popstates.each do |state|
- code += " when /\\b#{state}\\b/ : print line\n"
-end
-code += " end\nend\n"
-print "CODE IS\n---\n#{code}\n---\n" if false # turn on for debugging
-eval code
-
-# CODE IS
-# ---
-# ARGF.each do |line|
-# case line
-# when /\bCO\b/ : print line
-# when /\bON\b/ : print line
-# when /\bMI\b/ : print line
-# when /\bWI\b/ : print line
-# when /\bMN\b/ : print line
-# end
-# end
-#
-# ---
-
-# Note: (above) Ruby 1.8+ allows the 'when EXP : EXPR' on one line
-# with the colon separator.
-
-#-----------------------------
-#!/usr/bin/ruby
-# popgrep3 - grep for abbreviations of places that say "pop"
-# version3: build a match_any function
-popstates = %w(CO ON MI WI MN)
-expr = popstates.map{|e|"line =~ /\\b#{e}\\b/"}.join('||')
-eval "def match_any(line); #{expr};end"
-ARGF.each do |line|
- print line if match_any(line)
-end
-#-----------------------------
-
-## building a match_all function is a trivial
-## substitution of && for ||
-## here is a generalized example:
-#!/usr/bin/ruby -w
-## grepauth - print lines that mention both foo and bar
-class MultiMatch
- def initialize(*patterns)
- _any = build_match('||',patterns)
- _all = build_match('&&',patterns)
- eval "def match_any(line);#{_any};end\n"
- eval "def match_all(line);#{_all};end\n"
- end
- def build_match(sym,args)
- args.map{|e|"line =~ /#{e}/"}.join(sym)
- end
-end
-
-mm = MultiMatch.new('foo','bar')
-ARGF.each do |line|
- print line if mm.match_all(line)
-end
-#-----------------------------
-
-#!/usr/bin/ruby
-# popgrep4 - grep for abbreviations of places that say "pop"
-# version4: pretty fast, but simple: compile all re's first:
-popstates = %w(CO ON MI WI MN)
-popstates = popstates.map{|re| %r/\b#{re}\b/}
-ARGF.each do |line|
- popstates.each do |state_re|
- if line =~ state_re
- print line
- break
- end
- end
-end
-
-## speeds trials on the jargon file(412): 26006 lines, 1.3MB
-## popgrep1 => 7.040s
-## popgrep2 => 0.656s
-## popgrep2.5 => 0.633s
-## popgrep3 => 0.675s
-## popgrep4 => 1.027s
-
-# unless speed is criticial, the technique in popgrep4 is a
-# reasonable balance between speed and logical simplicity.
-
-
-# @@PLEAC@@_6.11
-begin
- print "Pattern? "
- pat = $stdin.gets.chomp
- Regexp.new(pat)
-rescue
- warn "Invalid Pattern"
- retry
-end
-
-
-# @@PLEAC@@_6.13
-# uses the 'amatch' extension found on:
-# http://raa.ruby-lang.org/project/amatch/
-require 'amatch'
-matcher = Amatch.new('balast')
-#$relative, $distance = 0, 1
-File.open('/usr/share/dict/words').each_line do |line|
- print line if matcher.search(line) <= 1
-end
-__END__
-#CODE
-ballast
-ballasts
-balustrade
-balustrades
-blast
-blasted
-blaster
-blasters
-blasting
-blasts
-
-
-# @@PLEAC@@_6.14
-str.scan(/\G(\d)/).each do |token|
- puts "found #{token}"
-end
-#-----------------------------
-n = " 49 here"
-n.gsub!(/\G /,'0')
-puts n
-#-----------------------------
-str = "3,4,5,9,120"
-str.scan(/\G,?(\d+)/).each do |num|
- puts "Found number: #{num}"
-end
-#-----------------------------
-# Ruby doesn't have the String.pos or a /c re modifier like Perl
-# But it does have StringScanner in the standard library (strscn)
-# which allows similar functionality:
-
-require 'strscan'
-text = 'the year 1752 lost 10 days on the 3rd of September'
-sc = StringScanner.new(text)
-while sc.scan(/.*?(\d+)/)
- print "found: #{sc[1]}\n"
-end
-if sc.scan(/\S+/)
- puts "Found #{sc[0]} after last number"
-end
-#-----------------------------
-# assuming continuing from above:
-puts "The position in 'text' is: #{sc.pos}"
-sc.pos = 30
-puts "The position in 'text' is: #{sc.pos}"
-
-
-# @@PLEAC@@_6.15
-#-----------------------------
-# greedy pattern
-str.gsub!(/<.*>/m,'') # not good
-
-# non-greedy (minimal) pattern
-str.gsub!(/<.*?>/m,'') # not great
-
-
-#-----------------------------
-#<b><i>this</i> and <i>that</i> are important</b> Oh, <b><i>me too!</i></b>
-#-----------------------------
-%r{ <b><i>(.*?)</i></b> }mx
-#-----------------------------
-%r/BEGIN((?:(?!BEGIN).)*)END/
-#-----------------------------
-%r{ <b><i>( (?: (?!</b>|</i>). )* ) </i></b> }mx
-#-----------------------------
-%r{ <b><i>( (?: (?!</[ib]>). )* ) </i></b> }mx
-#-----------------------------
-%r{
- <b><i>
- [^<]* # stuff not possibly bad, and not possibly the end.
- (?:
- # at this point, we can have '<' if not part of something bad
- (?! </?[ib]> ) # what we can't have
- < # okay, so match the '<'
- [^<]* # and continue with more safe stuff
- ) *
- </i></b>
- }mx
-
-
-# @@PLEAC@@_6.16
-#-----------------------------
-$/ = ""
-ARGF.each do |para|
- para.scan %r/
- \b # start at word boundary
- (\S+) # find chunk of non-whitespace
- \b # until a word boundary
- (
- \s+ # followed by whitespace
- \1 # and that same chunk again
- \b # and a word boundary
- ) + # one or more times
- /xi do
- puts "dup word '#{$1}' at paragraph #{$.}"
- end
-end
-#-----------------------------
-astr = 'nobody'
-bstr = 'bodysnatcher'
-if "#{astr} #{bstr}" =~ /^(\w+)(\w+) \2(\w+)$/
- print "#{$2} overlaps in #{$1}-#{$2}-#{$3}"
-end
-#-----------------------------
-#!/usr/bin/ruby -w
-# prime_pattern -- find prime factors of argument using patterns
-ARGV << 180
-cap = 'o' * ARGV.shift
-while cap =~ /^(oo+?)\1+$/
- print $1.size, " "
- cap.gsub!(/#{$1}/,'o')
-end
-puts cap.size
-#-----------------------------
-#diophantine
-# solve for 12x + 15y + 16z = 281, maximizing x
-if ('o' * 281).match(/^(o*)\1{11}(o*)\2{14}(o*)\3{15}$/)
- x, y, z = $1.size, $2.size, $3.size
- puts "One solution is: x=#{x}; y=#{y}; z=#{z}"
-else
- puts "No solution."
-end
-# => One solution is: x=17; y=3; z=2
-
-#-----------------------------
-# using different quantifiers:
-('o' * 281).match(/^(o+)\1{11}(o+)\2{14}(o+)\3{15}$/)
-# => One solution is: x=17; y=3; z=2
-
-('o' * 281).match(/^(o*?)\1{11}(o*)\2{14}(o*)\3{15}$/)
-# => One solution is: x=0; y=7; z=11
-
-('o' * 281).match(/^(o+?)\1{11}(o*)\2{14}(o*)\3{15}$/)
-# => One solution is: x=1; y=3; z=14
-
-
-# @@PLEAC@@_6.17
-# alpha OR beta
-%r/alpha|beta/
-
-# alpha AND beta
-%r/(?=.*alpha)(?=.*beta)/m
-
-# alpha AND beta, no overlap
-%r/alpha.*beta|beta.*alpha/m
-
-# NOT beta
-%r/^(?:(?!beta).)*$/m
-
-# NOT bad BUT good
-%r/(?=(?:(?!BAD).)*$)GOOD/m
-#-----------------------------
-
-if !(string =~ /pattern/) # ugly
- something()
-end
-
-if string !~ /pattern/ # preferred
- something()
-end
-
-
-#-----------------------------
-if string =~ /pat1/ && string =~ /pat2/
- something()
-end
-#-----------------------------
-if string =~ /pat1/ || string =~ /pat2/
- something()
-end
-#-----------------------------
-#!/usr/bin/ruby -w
-# minigrep - trivial grep
-pat = ARGV.shift
-ARGF.each do |line|
- print line if line =~ /#{pat}/o
-end
-#-----------------------------
- "labelled" =~ /^(?=.*bell)(?=.*lab)/m
-#-----------------------------
-$string =~ /bell/ && $string =~ /lab/
-#-----------------------------
-$murray_hill = "blah bell blah "
-if $murray_hill =~ %r{
- ^ # start of string
- (?= # zero-width lookahead
- .* # any amount of intervening stuff
- bell # the desired bell string
- ) # rewind, since we were only looking
- (?= # and do the same thing
- .* # any amount of intervening stuff
- lab # and the lab part
- )
- }mx # /m means . can match newline
-
- print "Looks like Bell Labs might be in Murray Hill!\n";
-end
-#-----------------------------
-"labelled" =~ /(?:^.*bell.*lab)|(?:^.*lab.*bell)/
-#-----------------------------
-$brand = "labelled";
-if $brand =~ %r{
- (?: # non-capturing grouper
- ^ .*? # any amount of stuff at the front
- bell # look for a bell
- .*? # followed by any amount of anything
- lab # look for a lab
- ) # end grouper
- | # otherwise, try the other direction
- (?: # non-capturing grouper
- ^ .*? # any amount of stuff at the front
- lab # look for a lab
- .*? # followed by any amount of anything
- bell # followed by a bell
- ) # end grouper
- }mx # /m means . can match newline
- print "Our brand has bell and lab separate.\n";
-end
-#-----------------------------
-$map =~ /^(?:(?!waldo).)*$/s
-#-----------------------------
-$map = "the great baldo"
-if $map =~ %r{
- ^ # start of string
- (?: # non-capturing grouper
- (?! # look ahead negation
- waldo # is he ahead of us now?
- ) # is so, the negation failed
- . # any character (cuzza /s)
- ) * # repeat that grouping 0 or more
- $ # through the end of the string
- }mx # /m means . can match newline
- print "There's no waldo here!\n";
-end
-=begin
- 7:15am up 206 days, 13:30, 4 users, load average: 1.04, 1.07, 1.04
-
-USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
-
-tchrist tty1 5:16pm 36days 24:43 0.03s xinit
-
-tchrist tty2 5:19pm 6days 0.43s 0.43s -tcsh
-
-tchrist ttyp0 chthon 7:58am 3days 23.44s 0.44s -tcsh
-
-gnat ttyS4 coprolith 2:01pm 13:36m 0.30s 0.30s -tcsh
-=end
-#% w | minigrep '^(?!.*ttyp).*tchrist'
-#-----------------------------
-%r{
- ^ # anchored to the start
- (?! # zero-width look-ahead assertion
- .* # any amount of anything (faster than .*?)
- ttyp # the string you don't want to find
- ) # end look-ahead negation; rewind to start
- .* # any amount of anything (faster than .*?)
- tchrist # now try to find Tom
-}x
-#-----------------------------
-#% w | grep tchrist | grep -v ttyp
-#-----------------------------
-#% grep -i 'pattern' files
-#% minigrep '(?i)pattern' files
-#-----------------------------
-
-
-# @@PLEAC@@_6.20
-ans = $stdin.gets.chomp
-re = %r/^#{Regexp.quote(ans)}/
-case
- when "SEND" =~ re : puts "Action is send"
- when "STOP" =~ re : puts "Action is stop"
- when "ABORT" =~ re : puts "Action is abort"
- when "EDIT" =~ re : puts "Action is edit"
-end
-#-----------------------------
-require 'abbrev'
-table = Abbrev.abbrev %w-send stop abort edit-
-loop do
- print "Action: "
- ans = $stdin.gets.chomp
- puts "Action for #{ans} is #{table[ans.downcase]}"
-end
-
-
-#-----------------------------
-# dummy values are defined for 'file', 'PAGER', and
-# the 'invoke_editor' and 'deliver_message' methods
-# do not do anything interesting in this example.
-#!/usr/bin/ruby -w
-require 'abbrev'
-
-file = 'pleac_ruby.data'
-PAGER = 'less'
-
-def invoke_editor
- puts "invoking editor"
-end
-
-def deliver_message
- puts "delivering message"
-end
-
-actions = {
- 'edit' => self.method(:invoke_editor),
- 'send' => self.method(:deliver_message),
- 'list' => proc {system(PAGER, file)},
- 'abort' => proc {puts "See ya!"; exit},
- "" => proc {puts "Unknown Command"}
-}
-
-dtable = Abbrev.abbrev(actions.keys)
-loop do
- print "Action: "
- ans = $stdin.gets.chomp.delete(" \t")
- actions[ dtable[ans.downcase] || "" ].call
-end
-
-
-# @@PLEAC@@_6.19
-#-----------------------------
-# basically, the Perl Cookbook categorizes this as an
-# unsolvable problem ...
-#-----------------------------
-1 while addr.gsub!(/\([^()]*\)/,'')
-#-----------------------------
-Dear someuser@host.com,
-
-Please confirm the mail address you gave us Wed May 6 09:38:41
-MDT 1998 by replying to this message. Include the string
-"Rumpelstiltskin" in that reply, but spelled in reverse; that is,
-start with "Nik...". Once this is done, your confirmed address will
-be entered into our records.
-
-
-# @@PLEAC@@_6.21
-#-----------------------------
-#% gunzip -c ~/mail/archive.gz | urlify > archive.urlified
-#-----------------------------
-#% urlify ~/mail/*.inbox > ~/allmail.urlified
-#-----------------------------
-#!/usr/bin/ruby -w
-# urlify - wrap HTML links around URL-like constructs
-
-urls = '(https?|telnet|gopher|file|wais|ftp)';
-ltrs = '\w';
-gunk = '/#~:.?+=&%@!\-';
-punc = '.:?\-';
-any = "#{ltrs}#{gunk}#{punc}";
-
-ARGF.each do |line|
- line.gsub! %r/
- \b # start at word boundary
- ( # begin $1 {
- #{urls} : # need resource and a colon
- [#{any}] +? # followed by on or more
- # of any valid character, but
- # be conservative and take only
- # what you need to....
- ) # end $1 }
- (?= # look-ahead non-consumptive assertion
- [#{punc}]* # either 0 or more punctuation
- [^#{any}] # followed by a non-url char
- | # or else
- $ # then end of the string
- )
- /iox do
- %Q|<A HREF="#{$1}">#{$1}</A>|
- end
- print line
-end
-
-
-# @@PLEAC@@_6.23
-%r/^m*(d?c{0,3}|c[dm])(l?x{0,3}|x[lc])(v?i{0,3}|i[vx])$/i
-#-----------------------------
-str.sub!(/(\S+)(\s+)(\S+)/, '\3\2\1')
-#-----------------------------
-%r/(\w+)\s*=\s*(.*)\s*$/ # keyword is $1, value is $2
-#-----------------------------
-%r/.{80,}/
-#-----------------------------
-%r|(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)|
-#-----------------------------
-str.gsub!(%r|/usr/bin|,'/usr/local/bin')
-#-----------------------------
-str.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/){ $1.hex.chr }
-#-----------------------------
-str.gsub!(%r{
- /\* # Match the opening delimiter
- .*? # Match a minimal number of characters
- \*/ # Match the closing delimiter
-}xm,'')
-#-----------------------------
-str.sub!(/^\s+/, '')
-str.sub!(/\s+$/, '')
-
-# but really, in Ruby we'd just do:
-str.strip!
-#-----------------------------
-str.gsub!(/\\n/,"\n")
-#-----------------------------
-str.sub!(/^.*::/, '')
-#-----------------------------
-%r/^([01]?\d\d|2[0-4]\d|25[0-5])\.([01]?\d\d|2[0-4]\d|25[0-5])\.
- ([01]?\d\d|2[0-4]\d|25[0-5])\.([01]?\d\d|2[0-4]\d|25[0-5])$/x
-#-----------------------------
-str.sub!(%r|^.*/|, '')
-#-----------------------------
-cols = ( (ENV['TERMCAP'] || " ") =~ /:co#(\d+):/ ) ? $1 : 80;
-#-----------------------------
-name = " #{$0} #{ARGV}".gsub(%r| /\S+/|, ' ')
-#-----------------------------
-require 'rbconfig'
-include Config
-raise "This isn't Linux" unless CONFIG['target_os'] =~ /linux/i;
-#-----------------------------
-str.gsub!(%r/\n\s+/, ' ')
-#-----------------------------
-nums = str.scan(/(\d+\.?\d*|\.\d+)/)
-#-----------------------------
-capwords = str.scan(%r/(\b[^\Wa-z0-9_]+\b)/)
-#-----------------------------
-lowords = str.scan(%r/(\b[^\WA-Z0-9_]+\b)/)
-#-----------------------------
-icwords = str.scan(%r/(\b[^\Wa-z0-9_][^\WA-Z0-9_]*\b)/)
-#-----------------------------
-links = str.scan(%r/<A[^>]+?HREF\s*=\s*["']?([^'" >]+?)[ '"]?>/mi)
-#-----------------------------
-initial = str =~ /^\S+\s+(\S)\S*\s+\S/ ? $1 : ""
-#-----------------------------
-str.gsub!(%r/"([^"]*)"/, %q-``\1''-)
-#-----------------------------
-
-$/ = ""
-sentences = []
-ARGF.each do |para|
- para.gsub!(/\n/, ' ')
- para.gsub!(/ {3,}/,' ')
- sentences << para.scan(/(\S.*?[!?.])(?= |\Z)/)
-end
-
-#-----------------------------
-%r/(\d{4})-(\d\d)-(\d\d)/ # YYYY in $1, MM in $2, DD in $3
-#-----------------------------
-%r/ ^
- (?:
- 1 \s (?: \d\d\d \s)? # 1, or 1 and area code
- | # ... or ...
- \(\d\d\d\) \s # area code with parens
- | # ... or ...
- (?: \+\d\d?\d? \s)? # optional +country code
- \d\d\d ([\s\-]) # and area code
- )
- \d\d\d (\s|\1) # prefix (and area code separator)
- \d\d\d\d # exchange
- $
- /x
-#-----------------------------
-%r/\boh\s+my\s+gh?o(d(dess(es)?|s?)|odness|sh)\b/i
-#-----------------------------
-lines = []
-lines << $1 while input.sub!(/^([^\012\015]*)(\012\015?|\015\012?)/,'')
-
-
-# @@PLEAC@@_7.0
-# An IO object being Enumerable, we can use 'each' directly on it
-File.open("/usr/local/widgets/data").each { |line|
- puts line if line =~ /blue/
-}
-
-logfile = File.new("/var/log/rubylog.txt", "w")
-mysub($stdin, logfile)
-
-# The method IO#readline is similar to IO#gets
-# but throws an exception when it reaches EOF
-f = File.new("bla.txt")
-begin
- while (line = f.readline)
- line.chomp
- $stdout.print line if line =~ /blue/
- end
-rescue EOFError
- f.close
-end
-
-while $stdin.gets # reads from STDIN
- unless (/\d/)
- $stderr.puts "No digit found." # writes to STDERR
- end
- puts "Read: #{$_}" # writes to STDOUT
-end
-
-logfile = File.new("/tmp/log", "w")
-
-logfile.close
-
-# $defout (or its synonym '$>') is the destination of output
-# for Kernel#print, Kernel#puts, and family functions
-logfile = File.new("log.txt", "w")
-old = $defout
-$defout = logfile # switch to logfile for output
-puts "Countdown initiated ..."
-$defout = old # return to original output
-puts "You have 30 seconds to reach minimum safety distance."
-
-
-# @@PLEAC@@_7.1
-source = File.new(path, "r") # open file "path" for reading only
-sink = File.new(path, "w") # open file "path" for writing only
-
-source = File.open(path, File::RDONLY) # open file "path" for reading only
-sink = File.open(path, File::WRONLY) # open file "path" for writing only
-
-file = File.open(path, "r+") # open "path" for reading and writing
-file = File.open(path, flags) # open "path" with the flags "flags" (see examples below for flags)
-
-# open file "path" read only
-file = File.open(path, "r")
-file = File.open(path, File::RDONLY)
-
-# open file "path" write only, create it if it does not exist
-# truncate it to zero length if it exists
-file = File.open(path, "w")
-file = File.open(path, File::WRONLY|File::TRUNC|File::CREAT)
-file = File.open(path, File::WRONLY|File::TRUNC|File::CREAT, 0666) # with permission 0666
-
-# open file "path" write only, fails if file exists
-file = File.open(path, File::WRONLY|File::EXCL|File::CREAT)
-file = File.open(path, File::WRONLY|File::EXCL|File::CREAT, 0666)
-
-# open file "path" for appending
-file = File.open(path, "a")
-file = File.open(path, File::WRONLY|File::APPEND|File::CREAT)
-file = File.open(path, File::WRONLY|File::APPEND|File::CREAT, 0666)
-
-# open file "path" for appending only when file exists
-file = File.open(path, File::WRONLY|File::APPEND)
-
-# open file "path" for reading and writing
-file = File.open(path, "r+")
-file = File.open(path, File::RDWR)
-
-# open file for reading and writing, create a new file if it does not exist
-file = File.open(path, File::RDWR|File::CREAT)
-file = File.open(path, File::RDWR|File::CREAT, 0600)
-
-# open file "path" reading and writing, fails if file exists
-file = File.open(path, File::RDWR|File::EXCL|File::CREAT)
-file = File.open(path, File::RDWR|File::EXCL|File::CREAT, 0600)
-
-
-# @@PLEAC@@_7.2
-# No problem with Ruby since the filename doesn't contain characters with
-# special meaning; like Perl's sysopen
-File.open(filename, 'r')
-
-
-# @@PLEAC@@_7.3
-File.expand_path('~root/tmp')
-#=> "/root/tmp"
-File.expand_path('~rpcuser')
-#=> "/var/lib/nfs"
-
-# To expand ~/.. it explicitely needs the environment variable HOME
-File.expand_path('~/tmp')
-#=> "/home/gc/tmp"
-
-
-# @@PLEAC@@_7.4
-# The exception raised in Ruby reports the filename
-File.open('afile')
-
-
-# @@PLEAC@@_7.5
-# Standard Ruby distribution provides the following useful extension
-require 'tempfile'
-# With the Tempfile class, the file is automatically deleted on garbage
-# collection, so you won't need to remove it, later on.
-tf = Tempfile.new('tmp') # a name is required to create the filename
-
-# If you need to pass the filename to an external program you can use
-# File#path, but don't forget to File#flush in order to flush anything
-# living in some buffer somewhere.
-tf.flush
-system("/usr/bin/dowhatever #{tf.path}")
-
-fh = Tempfile.new('tmp')
-fh.sync = true # autoflushes
-10.times { |i| fh.puts i }
-fh.rewind
-puts 'Tmp file has: ', fh.readlines
-
-
-# @@PLEAC@@_7.6
-while (DATA.gets) do
- # process the line
-end
-__END__
-# your data goes here
-# __DATA__ doesn't exist in Ruby
-
-#CODE
-# get info about the script (size, date of last modification)
-kilosize = DATA.stat.size / 1024
-last_modif = DATA.stat.mtime
-puts "<P>Script size is #{kilosize}"
-puts "<P>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 <tab> read from stdin
-
-opts = Getopt::Declare.new(<<'EOPARAM')
- ============
- Input Format:
- -i read from stdin
- ============
- Output Format:
- -l long listing
- -r reverse listing
- ============
- Sort on: (one of)
- -m mtime (modify time - default)
- {$sort_criteria = :mtime}
- -u atime (access time)
- {$sort_criteria = :atime}
- -c ctime (inode change time)
- {$sort_criteria = :ctime}
- -s size
- {$sort_criteria = :size}
- [mutex: -m -u -c -s]
-
-EOPARAM
-
-$sort_criteria ||= :mtime
-files = {}
-DIRS = opts['-i'] ? $stdin.readlines.map{|f|f.chomp!} : ARGV
-DIRS.each do |dir|
- Find.find(dir) do |ent|
- files[ent] = File::stat(ent)
- end
-end
-entries = files.keys.sort_by{|f| files[f].send($sort_criteria)}
-entries = entries.reverse unless opts['-r']
-
-entries.each do |ent|
- unless opts['-l']
- puts ent
- next
- end
- stats = files[ent]
- ftime = stats.send($sort_criteria == :size ? :mtime : $sort_criteria)
- printf "%6d %04o %6d %8s %8s %8d %s %s\n",
- stats.ino,
- stats.mode & 07777,
- stats.nlink,
- ETC::PASSWD[stats.uid].name,
- ETC::GROUP[stats.gid].name,
- stats.size,
- ftime.strftime("%a %b %d %H:%M:%S %Y"),
- ent
-end
-
-
-# @@PLEAC@@_10.0
-def hello
- $greeted += 1 # in Ruby, a variable beginning with $ is global (can be any type of course)
- puts "hi there!"
-end
-
-# We need to initialize $greeted before it can be used, because "+=" is waiting a Numeric object
-$greeted = 0
-hello # note that appending () is optional to function calls with no parameters
-
-
-# @@PLEAC@@_10.1
-# In Ruby, parameters are named anyway
-def hypotenuse(side1, side2)
- Math.sqrt(side1**2 + side2**2) # the sqrt function comes from the Math module
-end
-diag = hypotenuse(3, 4)
-
-puts hypotenuse(3, 4)
-
-a = [3, 4]
-print hypotenuse(*a) # the star operator will magically convert an Array into a "tuple"
-
-both = men + women
-
-# In Ruby, all objects are references, so the same problem arises; we then return a new object
-nums = [1.4, 3.5, 6.7]
-def int_all(n)
- n.collect { |v| v.to_i }
-end
-ints = int_all(nums)
-
-nums = [1.4, 3.5, 6.7]
-def trunc_em(n)
- n.collect! { |v| v.to_i } # the bang-version of collect modifies the object
-end
-trunc_em(nums)
-
-# Ruby has two chomp version:
-# ``chomp'' chomps the record separator and returns what's expected
-# ``chomp!'' does the same but also modifies the parameter object
-