blob: 80e0249975f3dc60262254d92c0c70ca20a0f976 [file] [log] [blame]
###############################################################################
# Copyright (c) 2005, 2007 IBM Corporation and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0.
#
# SPDX-License-Identifier: EPL-2.0
#
###############################################################################
class DLTKBuiltinGeneratorSet
include Enumerable
# Creates a new set containing the given objects.
def self.[](*ary)
new(ary)
end
# Creates a new set containing the elements of the given enumerable
# object.
#
# If a block is given, the elements of enum are preprocessed by the
# given block.
def initialize(enum = nil, &block) # :yields: o
@hash ||= Hash.new
enum.nil? and return
if block
enum.each { |o| add(block[o]) }
else
merge(enum)
end
end
# Copy internal hash.
def initialize_copy(orig)
@hash = orig.instance_eval{@hash}.dup
end
# Returns the number of elements.
def size
@hash.size
end
alias length size
# Returns true if the set contains no elements.
def empty?
@hash.empty?
end
# Removes all elements and returns self.
def clear
@hash.clear
self
end
# Replaces the contents of the set with the contents of the given
# enumerable object and returns self.
def replace(enum)
if enum.class == self.class
@hash.replace(enum.instance_eval { @hash })
else
enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
clear
enum.each { |o| add(o) }
end
self
end
# Converts the set to an array. The order of elements is uncertain.
def to_a
@hash.keys
end
def flatten_merge(set, seen = DLTKBuiltinGeneratorSet.new)
set.each { |e|
if e.is_a?(DLTKBuiltinGeneratorSet)
if seen.include?(e_id = e.object_id)
raise ArgumentError, "tried to flatten recursive Set"
end
seen.add(e_id)
flatten_merge(e, seen)
seen.delete(e_id)
else
add(e)
end
}
self
end
protected :flatten_merge
# Returns a new set that is a copy of the set, flattening each
# containing set recursively.
def flatten
self.class.new.flatten_merge(self)
end
# Equivalent to Set#flatten, but replaces the receiver with the
# result in place. Returns nil if no modifications were made.
def flatten!
if detect { |e| e.is_a?(DLTKBuiltinGeneratorSet) }
replace(flatten())
else
nil
end
end
# Returns true if the set contains the given object.
def include?(o)
@hash.include?(o)
end
alias member? include?
# Returns true if the set is a superset of the given set.
def superset?(set)
set.is_a?(DLTKBuiltinGeneratorSet) or raise ArgumentError, "value must be a set"
return false if size < set.size
set.all? { |o| include?(o) }
end
# Returns true if the set is a proper superset of the given set.
def proper_superset?(set)
set.is_a?(DLTKBuiltinGeneratorSet) or raise ArgumentError, "value must be a set"
return false if size <= set.size
set.all? { |o| include?(o) }
end
# Returns true if the set is a subset of the given set.
def subset?(set)
set.is_a?(DLTKBuiltinGeneratorSet) or raise ArgumentError, "value must be a set"
return false if set.size < size
all? { |o| set.include?(o) }
end
# Returns true if the set is a proper subset of the given set.
def proper_subset?(set)
set.is_a?(DLTKBuiltinGeneratorSet) or raise ArgumentError, "value must be a set"
return false if set.size <= size
all? { |o| set.include?(o) }
end
# Calls the given block once for each element in the set, passing
# the element as parameter.
def each
@hash.each_key { |o| yield(o) }
self
end
# Adds the given object to the set and returns self. Use +merge+ to
# add several elements at once.
def add(o)
@hash[o] = true
self
end
alias << add
# Adds the given object to the set and returns self. If the
# object is already in the set, returns nil.
def add?(o)
if include?(o)
nil
else
add(o)
end
end
# Deletes the given object from the set and returns self. Use +subtract+ to
# delete several items at once.
def delete(o)
@hash.delete(o)
self
end
# Deletes the given object from the set and returns self. If the
# object is not in the set, returns nil.
def delete?(o)
if include?(o)
delete(o)
else
nil
end
end
# Deletes every element of the set for which block evaluates to
# true, and returns self.
def delete_if
@hash.delete_if { |o,| yield(o) }
self
end
# Do collect() destructively.
def collect!
set = self.class.new
each { |o| set << yield(o) }
replace(set)
end
alias map! collect!
# Equivalent to Set#delete_if, but returns nil if no changes were
# made.
def reject!
n = size
delete_if { |o| yield(o) }
size == n ? nil : self
end
# Merges the elements of the given enumerable object to the set and
# returns self.
def merge(enum)
if enum.is_a?(DLTKBuiltinGeneratorSet)
@hash.update(enum.instance_eval { @hash })
else
enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
enum.each { |o| add(o) }
end
self
end
# Deletes every element that appears in the given enumerable object
# and returns self.
def subtract(enum)
enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
enum.each { |o| delete(o) }
self
end
# Returns a new set built by merging the set and the elements of the
# given enumerable object.
def |(enum)
enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
dup.merge(enum)
end
alias + | ##
alias union | ##
# Returns a new set built by duplicating the set, removing every
# element that appears in the given enumerable object.
def -(enum)
enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
dup.subtract(enum)
end
alias difference - ##
# Returns a new set containing elements common to the set and the
# given enumerable object.
def &(enum)
enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
n = self.class.new
enum.each { |o| n.add(o) if include?(o) }
n
end
alias intersection & ##
# Returns a new set containing elements exclusive between the set
# and the given enumerable object. (set ^ enum) is equivalent to
# ((set | enum) - (set & enum)).
def ^(enum)
enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable"
n = DLTKBuiltinGeneratorSet.new(enum)
each { |o| if n.include?(o) then n.delete(o) else n.add(o) end }
n
end
# Returns true if two sets are equal. The equality of each couple
# of elements is defined according to Object#eql?.
def ==(set)
equal?(set) and return true
set.is_a?(DLTKBuiltinGeneratorSet) && size == set.size or return false
hash = @hash.dup
set.all? { |o| hash.include?(o) }
end
def hash # :nodoc:
@hash.hash
end
def eql?(o) # :nodoc:
return false unless o.is_a?(DLTKBuiltinGeneratorSet)
@hash.eql?(o.instance_eval{@hash})
end
# Classifies the set by the return value of the given block and
# returns a hash of {value => set of elements} pairs. The block is
# called once for each element of the set, passing the element as
# parameter.
#
# e.g.:
#
# require 'set'
# files = Set.new(Dir.glob("*.rb"))
# hash = files.classify { |f| File.mtime(f).year }
# p hash # => {2000=>#<Set: {"a.rb", "b.rb"}>,
# # 2001=>#<Set: {"c.rb", "d.rb", "e.rb"}>,
# # 2002=>#<Set: {"f.rb"}>}
def classify # :yields: o
h = {}
each { |i|
x = yield(i)
(h[x] ||= self.class.new).add(i)
}
h
end
# Divides the set into a set of subsets according to the commonality
# defined by the given block.
#
# If the arity of the block is 2, elements o1 and o2 are in common
# if block.call(o1, o2) is true. Otherwise, elements o1 and o2 are
# in common if block.call(o1) == block.call(o2).
#
# e.g.:
#
# require 'set'
# numbers = Set[1, 3, 4, 6, 9, 10, 11]
# set = numbers.divide { |i,j| (i - j).abs == 1 }
# p set # => #<Set: {#<Set: {1}>,
# # #<Set: {11, 9, 10}>,
# # #<Set: {3, 4}>,
# # #<Set: {6}>}>
def divide(&func)
if func.arity == 2
require 'tsort'
class << dig = {} # :nodoc:
include TSort
alias tsort_each_node each_key
def tsort_each_child(node, &block)
fetch(node).each(&block)
end
end
each { |u|
dig[u] = a = []
each{ |v| func.call(u, v) and a << v }
}
set = DLTKBuiltinGeneratorSet.new()
dig.each_strongly_connected_component { |css|
set.add(self.class.new(css))
}
set
else
DLTKBuiltinGeneratorSet.new(classify(&func).values)
end
end
InspectKey = :__inspect_key__ # :nodoc:
# Returns a string containing a human-readable representation of the
# set. ("#<Set: {element1, element2, ...}>")
def inspect
ids = (Thread.current[InspectKey] ||= [])
if ids.include?(object_id)
return sprintf('#<%s: {...}>', self.class.name)
end
begin
ids << object_id
return sprintf('#<%s: {%s}>', self.class, to_a.inspect[1..-2])
ensure
ids.pop
end
end
def pretty_print(pp) # :nodoc:
pp.text sprintf('#<%s: {', self.class.name)
pp.nest(1) {
pp.seplist(self) { |o|
pp.pp o
}
}
pp.text "}>"
end
def pretty_print_cycle(pp) # :nodoc:
pp.text sprintf('#<%s: {%s}>', self.class.name, empty? ? '' : '...')
end
end
class DLTKBuiltinGenerator
def collectMethod(hash, methodName, arity)
hash.add methodName + '###' + arity.to_s
end
def put_methods!(metaclass)
result = DLTKBuiltinGeneratorSet.new
modules = metaclass.included_modules
methods = metaclass.public_instance_methods(false)
for mod in modules do; methods -= mod.public_instance_methods(true); end
$data << "\t\npublic\n"
for method in methods do
arity = metaclass.instance_method(method).arity
collectMethod(result, method.to_s, arity)
put_rdoc(metaclass.name + "." + method.to_s)
$data << <<-"END"
def #{method.to_s}(#{generateArgs(arity)})
end
END
end
methods = metaclass.protected_instance_methods(false)
for mod in modules do;
if mod.respond_to?(:protected_instance_methods) then
methods -= mod.protected_instance_methods(true)
end
end
$data << "\t\nprotected\n"
for method in methods do
put_rdoc(metaclass.name + "." + method.to_s)
arity = metaclass.instance_method(method).arity
collectMethod(result, method.to_s, arity)
$data << <<-"END"
def #{method.to_s}(#{generateArgs(arity)})
end
END
end
methods = metaclass.private_instance_methods(false)
for mod in modules do;
if mod.respond_to?(:private_instance_methods) then
methods -= mod.private_instance_methods(true)
end
end
$data << "\t\nprivate\n"
for method in methods do
put_rdoc(metaclass.name + "." + method.to_s)
arity = metaclass.instance_method(method).arity
collectMethod(result, method.to_s, arity)
$data << <<-"END"
def #{method.to_s}(#{generateArgs(arity)})
end
END
end
return result
end
def generateArgs(arity)
if arity < 0 then
return "*args"
end
result = ""
for i in 1..arity do
result << "arg" + i.to_s
if i != arity then
result << ", "
end
end
result
end
def put_singleton_methods!(metaclass, instanceMethods)
# if (metaclass.is_a?(Class))
# $data << <<-"END2"
# class << self
# END2
# else
# $data << "\t\tprivate\n"
# end
# ms = (metaclass.public_methods(false) - Class.instance_methods(false)).each { |m|
ms = (metaclass.singleton_methods(false)).each { |m|
arity = metaclass.method(m).arity
if (!instanceMethods.include?(m.to_s + '###' + arity.to_s)) then
$data << <<-"END2"
def self.#{m.to_s}(#{generateArgs(arity)})
end
END2
end
}
# if (metaclass.is_a?(Class))
# $data << <<-"END2"
# end
# END2
# end
end
def put_included_modules!(metaclass)
ms = (metaclass.included_modules -
((metaclass.is_a?(Class) &&
metaclass.superclass &&
metaclass.superclass.included_modules) || []))
for in_mod in ms do
$data << <<-"END"
include #{in_mod.name}
END
end
end
def put_singleton_included_modules!(metaclass)
$data << <<-"END2"
class << ::#{metaclass.name}
END2
sup = (class << metaclass; superclass; end)
# ms = ((class << metaclass; included_modules; end) -
# ((sup && sup.included_modules) || []))
ms = (class << metaclass; included_modules; end)
for in_mod in ms do
$data << <<-"END"
include #{in_mod.name}
END
end
$data << <<-"END2"
end
END2
end
def put_constants(metaclass)
#return
consts = DLTKBuiltinGeneratorSet.new(metaclass.constants)
ancestors = metaclass.ancestors
for m in ancestors
if m != metaclass
consts -= DLTKBuiltinGeneratorSet.new(m.constants)
end
end
for c in consts
v = metaclass.const_get(c)
if !@classesAndModules.include?(v)
$data << c.to_s + '=' + v.class.to_s + ".new\n"
end
end
end
def put_superclass!(metaclass)
return if metaclass.superclass.nil?
$data << <<-"END"
#{const_for(metaclass)}.setSuperClass(#{const_for(metaclass.superclass)});
END
end
#def put_singleton_superclass!(metaclass)
# $data << <<-"END"
# #{const_for_singleton(metaclass)}.setSuperClass(#{const_for(metaclass.class)});
# END
#end
def dumpClass(klass)
name = klass.name
if name == "NameError::message" || name == "fatal" then
return
end
sc = klass.superclass
if sc then scname = " < ::" + sc.name else scname = "" end
# methods = klass.instance_methods(false)
put_rdoc(name)
$data << <<-"END"
class #{name} #{scname}
END
put_included_modules!(klass)
if sc then
# skip Object - they are generated later
put_constants(klass)
end
put_singleton_included_modules!(klass)
instanceMethods = put_methods!(klass)
put_singleton_methods!(klass, instanceMethods)
$data << <<-"END"
end
END
end
def put_rdoc(name)
return
print "Getting doc for " + name + "\n"
rdoc = `d:\\instantrails\\ruby\\bin\\ri.bat \"#{name}\" -f html`
rdoc.to_a.each { |line|
$data << "#" + line
}
end
def dumpModule(klass)
name = klass.name
# methods = klass.instance_methods(false)
put_rdoc(name)
$data << <<-"END"
module #{name}
END
put_included_modules!(klass)
put_constants(klass)
instanceMethods = put_methods!(klass)
put_singleton_methods!(klass, instanceMethods)
$data << <<-"END"
end
END
end
def dumpVariables
$data << "# Global variables\n"
global_variables.each { |var|
$data << <<-"END"
#{var.to_s} = #{var.to_s}
END
}
end
def process_all
classes = DLTKBuiltinGeneratorSet.new
known_modules = DLTKBuiltinGeneratorSet.new
ObjectSpace.each_object do |o|
if (o.respond_to?('name')) then
className = o.name
if className == 'DLTKBuiltinGenerator' || className == 'DLTKBuiltinGeneratorSet' || className == nil then
next
end
end
classes << o if o.is_a?(Class)
known_modules << o if o.is_a?(Module)
end
@classesAndModules = known_modules + classes
known_modules = (known_modules - classes).to_a
classes = classes.to_a.sort { |a,b| a.name <=> b.name }
classes.each { |c|
$data = ""
dumpClass(c)
filename = c.name
pos = filename.index(':')
if pos then
filename = filename.slice(0..pos-1)
#puts "sliced " + filename
end
file = filename + ".rb"
puts "#### DLTK RUBY BUILTINS ####" + file + "\n"
puts $data
#File.open(file, 'a') {|f| f.write $data}
}
known_modules.each { |c|
$data = ""
dumpModule(c)
filename = c.name
pos = filename.index(':')
if pos then
filename = filename.slice(0..pos-1)
#puts "sliced " + filename
end
file = filename + ".rb"
puts "#### DLTK RUBY BUILTINS ####" + file + "\n"
puts $data
#File.open(file, 'a') {|f| f.write $data}
}
ccc = []
Module.constants.each { |x|
ccc << x.to_s
}
ccc.delete('DLTKBuiltinGenerator')
ccc.delete('DLTKBuiltinGeneratorSet')
known_modules.each { |x|
ccc.delete(x.to_s)
}
classes.each { |x|
ccc.delete(x.to_s)
}
puts "#### DLTK RUBY BUILTINS ####constants.rb\n\n\n"
ccc.each { |bar|
puts "#{bar} = #{Module.const_get(bar).class.to_s}.new"
}
end
end
g = DLTKBuiltinGenerator.new
g.process_all
# vim: noexpandtab tabstop=4 sts=0 sw=4