ruckus 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +22 -0
- data/README +0 -0
- data/README.markdown +51 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/lib/ruckus.rb +70 -0
- data/lib/ruckus/blob.rb +113 -0
- data/lib/ruckus/choice.rb +55 -0
- data/lib/ruckus/dfuzz.rb +231 -0
- data/lib/ruckus/dictionary.rb +119 -0
- data/lib/ruckus/enum.rb +39 -0
- data/lib/ruckus/extensions/array.rb +33 -0
- data/lib/ruckus/extensions/class.rb +168 -0
- data/lib/ruckus/extensions/duplicable.rb +37 -0
- data/lib/ruckus/extensions/file.rb +24 -0
- data/lib/ruckus/extensions/fixnum.rb +26 -0
- data/lib/ruckus/extensions/hash.rb +10 -0
- data/lib/ruckus/extensions/integer.rb +26 -0
- data/lib/ruckus/extensions/ipaddr.rb +155 -0
- data/lib/ruckus/extensions/irb.rb +30 -0
- data/lib/ruckus/extensions/math.rb +6 -0
- data/lib/ruckus/extensions/module.rb +37 -0
- data/lib/ruckus/extensions/numeric.rb +117 -0
- data/lib/ruckus/extensions/object.rb +22 -0
- data/lib/ruckus/extensions/range.rb +16 -0
- data/lib/ruckus/extensions/socket.rb +20 -0
- data/lib/ruckus/extensions/string.rb +327 -0
- data/lib/ruckus/filter.rb +16 -0
- data/lib/ruckus/human_display.rb +79 -0
- data/lib/ruckus/ip.rb +38 -0
- data/lib/ruckus/mac_addr.rb +31 -0
- data/lib/ruckus/mutator.rb +318 -0
- data/lib/ruckus/null.rb +24 -0
- data/lib/ruckus/number.rb +360 -0
- data/lib/ruckus/parsel.rb +363 -0
- data/lib/ruckus/selector.rb +92 -0
- data/lib/ruckus/str.rb +164 -0
- data/lib/ruckus/structure.rb +263 -0
- data/lib/ruckus/structure/atcreate.rb +23 -0
- data/lib/ruckus/structure/beforebacks.rb +28 -0
- data/lib/ruckus/structure/defaults.rb +57 -0
- data/lib/ruckus/structure/factory.rb +42 -0
- data/lib/ruckus/structure/fixupfields.rb +16 -0
- data/lib/ruckus/structure/initializers.rb +14 -0
- data/lib/ruckus/structure/relate.rb +34 -0
- data/lib/ruckus/structure/replacement.rb +30 -0
- data/lib/ruckus/structure/searchmods.rb +33 -0
- data/lib/ruckus/structure/structureproxies.rb +28 -0
- data/lib/ruckus/structure/validate.rb +12 -0
- data/lib/ruckus/structure_shortcuts.rb +109 -0
- data/lib/ruckus/time_t.rb +26 -0
- data/lib/ruckus/vector.rb +97 -0
- data/ruckus.gemspec +104 -0
- data/test/test_decides.rb +61 -0
- data/test/test_mutator.rb +29 -0
- data/test/test_override.rb +23 -0
- data/test/test_replace.rb +39 -0
- metadata +138 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
# === A collection of objects of which only one is active at any particular time
|
2
|
+
|
3
|
+
module Ruckus
|
4
|
+
# A Dictionary is a collection of data objects of which only one is
|
5
|
+
# active at any particular time. This class extends and provies a simplified
|
6
|
+
# front-end for Choice.
|
7
|
+
#
|
8
|
+
class Dictionary < Choice
|
9
|
+
attr_accessor :dict, :selection
|
10
|
+
|
11
|
+
# Initializes a new Dictionary object.
|
12
|
+
# Parameters may be provided at initialisation to control the behaviour
|
13
|
+
# of an object. These params are:
|
14
|
+
#
|
15
|
+
# dict An indexable (generally hash or array) object with indexed
|
16
|
+
# values mapped to the possible data objects. (see notes below)
|
17
|
+
# Any indexable object using the [] method can be used,
|
18
|
+
# provided that 'selection' returns a valid index. If a type
|
19
|
+
# is to have parameters passed to it, then it should be
|
20
|
+
# provided as [type, hash_params]
|
21
|
+
#
|
22
|
+
# selection An index into :dict which specifies the currently
|
23
|
+
# active choice.
|
24
|
+
#
|
25
|
+
# default An optional parameter specifying the default class
|
26
|
+
# to capture to.
|
27
|
+
#
|
28
|
+
# A selection may be any of the following:
|
29
|
+
#
|
30
|
+
# - Immediate Value:
|
31
|
+
# An immediate value to be used as the index. Fixnum
|
32
|
+
#
|
33
|
+
# - Symbol:
|
34
|
+
# A symbol which will be will be searched with 'find_tag' from the
|
35
|
+
# root of the parent structure. The value of the tagged element is used
|
36
|
+
# as the index.
|
37
|
+
# - By default a type symbol will be converted to an immediate name and
|
38
|
+
# pulled from the Ruckus namespace.
|
39
|
+
# - To specify another namespace, use the :dict_from parameter as in
|
40
|
+
# ":dict_from => Name::Space". A :dict_from namespace can be
|
41
|
+
# set globally or overidden as a per choice parameter.
|
42
|
+
#
|
43
|
+
# - Proc/Lambda:
|
44
|
+
# The lambda or proc is called and passed the following parameters:
|
45
|
+
#
|
46
|
+
# 'buf' - The capture buffer
|
47
|
+
# 'this' - A reference to the current choice structure.
|
48
|
+
#
|
49
|
+
# The lambda must return either of the following
|
50
|
+
#
|
51
|
+
# An immediate value for the index to select
|
52
|
+
#
|
53
|
+
# An array pair consisting of the immediate value and sub-string
|
54
|
+
# buffer for the selection.
|
55
|
+
#
|
56
|
+
# NOTE: The latter form allows the proc to perform its own internal
|
57
|
+
# 'captures'. The proc is expected to remove (slice!) any contents
|
58
|
+
# from the original buffer for whatever extractions are made with
|
59
|
+
# 'capture'.
|
60
|
+
#
|
61
|
+
def initialize(opts={})
|
62
|
+
@dict = (opts[:dict] || [])
|
63
|
+
@selection = (opts[:selection] || nil)
|
64
|
+
@dict_from = (opts[:dict_from] || Ruckus)
|
65
|
+
@default = opts[:default]
|
66
|
+
|
67
|
+
# This lambda is passed to the 'choice' superclass to provide
|
68
|
+
# all the dictionary functionality.
|
69
|
+
block = lambda do |buf, this|
|
70
|
+
lambuf = nil
|
71
|
+
case @selection
|
72
|
+
when Symbol
|
73
|
+
sel = (x=this.root.find_tag(@selection) and x.value)
|
74
|
+
when Proc
|
75
|
+
sel, lambuf = @selection.call(buf,this)
|
76
|
+
else
|
77
|
+
sel = @selection
|
78
|
+
end
|
79
|
+
|
80
|
+
if (k = @dict[sel]) or (k = @default)
|
81
|
+
ksym, *args = k
|
82
|
+
return buf unless ksym
|
83
|
+
|
84
|
+
unless args[-1].kind_of?(Hash) and nsp=args[-1][:dict_from]
|
85
|
+
nsp = @dict_from
|
86
|
+
end
|
87
|
+
|
88
|
+
klass = if (ksym.kind_of? Class or ksym.kind_of? Module)
|
89
|
+
ksym
|
90
|
+
else
|
91
|
+
ksym.to_s.const_lookup(nsp) or return(buf)
|
92
|
+
end
|
93
|
+
|
94
|
+
choice = klass.new(*args)
|
95
|
+
choice.parent = this.value.parent
|
96
|
+
this.value = choice
|
97
|
+
|
98
|
+
if not lambuf.nil?
|
99
|
+
return buf if x=this.value.capture(lambuf) and x.empty?
|
100
|
+
else
|
101
|
+
this.value.capture(buf)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
super( opts.merge(:block => block) )
|
107
|
+
end
|
108
|
+
|
109
|
+
end # class Dictionary
|
110
|
+
|
111
|
+
class Structure
|
112
|
+
# Convenience alias for 'dictionary'. First arg is "name", all others
|
113
|
+
# are passed directly into 'new'
|
114
|
+
def self.dict(*args)
|
115
|
+
with_args(*args) {|name, opts| dictionary opts.merge(:name => name)}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
end # module Ruckus
|
data/lib/ruckus/enum.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
module Ruckus
|
3
|
+
class Enum < Number
|
4
|
+
attr_accessor :enums
|
5
|
+
|
6
|
+
def initialize(opts={})
|
7
|
+
super(opts)
|
8
|
+
@enums ||= []
|
9
|
+
raise "enums must be Enumerable" unless @enums.kind_of? Enumerable
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_human(indent="")
|
13
|
+
"#{indent}#{@name} = #{@value}(#{@value.to_hex}) [ #{ ((n=lookup)? n : "???").to_s } ]"
|
14
|
+
end
|
15
|
+
|
16
|
+
def lookup
|
17
|
+
if (o=@enums[@value]).kind_of?(Hash) then o[:name] else o end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Structure
|
22
|
+
def self.enum16le(*args)
|
23
|
+
with_args(*args) {|name, opts| enum name, opts.merge(:width => 16, :endian => :little)}
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.enum32le(*args)
|
27
|
+
with_args(*args) {|name, opts| enum name, opts.merge(:width => 32, :endian => :little)}
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.enum16be(*args)
|
31
|
+
with_args(*args) {|name, opts| enum name, opts.merge(:width => 16, :endian => :big)}
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.enum32be(*args)
|
35
|
+
with_args(*args) {|name, opts| enum name, opts.merge(:width => 32, :endian => :big)}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Array
|
2
|
+
module ArrayExtensions
|
3
|
+
# Assume an array of key, value tuples, and convert to Hash
|
4
|
+
def to_hash
|
5
|
+
r = {}
|
6
|
+
each {|it| r[it[0]] = it[1]}
|
7
|
+
return r
|
8
|
+
end
|
9
|
+
|
10
|
+
def kind_of_these? y
|
11
|
+
inject(false) {|acc, klass| acc || y.kind_of?(klass)}
|
12
|
+
end
|
13
|
+
|
14
|
+
#return first hash-like element with key k
|
15
|
+
def kassoc(k)
|
16
|
+
# XXX not used
|
17
|
+
each { |h| return h if h.try(:has_key?, k) }
|
18
|
+
return nil
|
19
|
+
end
|
20
|
+
|
21
|
+
#return first hash-like element with value v
|
22
|
+
def vassoc(v)
|
23
|
+
# XXX not used
|
24
|
+
each { |h| return h if h.try(:has_value?, v) }
|
25
|
+
return nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def extract_options!
|
29
|
+
last.is_a?(::Hash) ? pop : {}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
include ArrayExtensions
|
33
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
class Class
|
2
|
+
module ClassExtensions
|
3
|
+
# Also crazy that this isn't in the library
|
4
|
+
def inherits_from?(klass)
|
5
|
+
return true if self == klass
|
6
|
+
return true if self.superclass == klass
|
7
|
+
return false if self.superclass == Object
|
8
|
+
|
9
|
+
rec = lambda do |x|
|
10
|
+
if x == Object
|
11
|
+
false
|
12
|
+
elsif x == klass
|
13
|
+
true
|
14
|
+
else
|
15
|
+
rec.call(x.superclass)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
rec.call(self)
|
20
|
+
end
|
21
|
+
|
22
|
+
def alias_cmethod(to, from)
|
23
|
+
# XXX not used
|
24
|
+
(class << self;self;end).class_eval {
|
25
|
+
define_method to do |*args|
|
26
|
+
send(from, *args)
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
|
33
|
+
# their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
|
34
|
+
# to, for example, an array without those additions being shared with either their parent, siblings, or
|
35
|
+
# children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
|
36
|
+
def class_inheritable_reader(*syms)
|
37
|
+
syms.each do |sym|
|
38
|
+
next if sym.is_a?(Hash)
|
39
|
+
class_eval <<-EOS
|
40
|
+
def self.#{sym}
|
41
|
+
read_inheritable_attribute(:#{sym})
|
42
|
+
end
|
43
|
+
|
44
|
+
def #{sym}
|
45
|
+
self.class.#{sym}
|
46
|
+
end
|
47
|
+
EOS
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def class_inheritable_writer(*syms)
|
52
|
+
options = syms.extract_options!
|
53
|
+
syms.each do |sym|
|
54
|
+
class_eval <<-EOS
|
55
|
+
def self.#{sym}=(obj)
|
56
|
+
write_inheritable_attribute(:#{sym}, obj)
|
57
|
+
end
|
58
|
+
|
59
|
+
#{"
|
60
|
+
def #{sym}=(obj)
|
61
|
+
self.class.#{sym} = obj
|
62
|
+
end
|
63
|
+
" unless options[:instance_writer] == false }
|
64
|
+
EOS
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def class_inheritable_array_writer(*syms)
|
69
|
+
options = syms.extract_options!
|
70
|
+
syms.each do |sym|
|
71
|
+
class_eval <<-EOS
|
72
|
+
def self.#{sym}=(obj)
|
73
|
+
write_inheritable_array(:#{sym}, obj)
|
74
|
+
end
|
75
|
+
|
76
|
+
#{"
|
77
|
+
def #{sym}=(obj)
|
78
|
+
self.class.#{sym} = obj
|
79
|
+
end
|
80
|
+
" unless options[:instance_writer] == false }
|
81
|
+
EOS
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def class_inheritable_hash_writer(*syms)
|
86
|
+
options = syms.extract_options!
|
87
|
+
syms.each do |sym|
|
88
|
+
class_eval <<-EOS
|
89
|
+
def self.#{sym}=(obj)
|
90
|
+
write_inheritable_hash(:#{sym}, obj)
|
91
|
+
end
|
92
|
+
|
93
|
+
#{"
|
94
|
+
def #{sym}=(obj)
|
95
|
+
self.class.#{sym} = obj
|
96
|
+
end
|
97
|
+
" unless options[:instance_writer] == false }
|
98
|
+
EOS
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def class_inheritable_accessor(*syms)
|
103
|
+
class_inheritable_reader(*syms)
|
104
|
+
class_inheritable_writer(*syms)
|
105
|
+
end
|
106
|
+
|
107
|
+
def class_inheritable_array(*syms)
|
108
|
+
class_inheritable_reader(*syms)
|
109
|
+
class_inheritable_array_writer(*syms)
|
110
|
+
end
|
111
|
+
|
112
|
+
def class_inheritable_hash(*syms)
|
113
|
+
class_inheritable_reader(*syms)
|
114
|
+
class_inheritable_hash_writer(*syms)
|
115
|
+
end
|
116
|
+
|
117
|
+
def inheritable_attributes
|
118
|
+
@inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
|
119
|
+
end
|
120
|
+
|
121
|
+
def write_inheritable_attribute(key, value)
|
122
|
+
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
|
123
|
+
@inheritable_attributes = {}
|
124
|
+
end
|
125
|
+
inheritable_attributes[key] = value
|
126
|
+
end
|
127
|
+
|
128
|
+
def write_inheritable_array(key, elements)
|
129
|
+
write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
|
130
|
+
write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
|
131
|
+
end
|
132
|
+
|
133
|
+
def write_inheritable_hash(key, hash)
|
134
|
+
write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
|
135
|
+
write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
|
136
|
+
end
|
137
|
+
|
138
|
+
def read_inheritable_attribute(key)
|
139
|
+
inheritable_attributes[key]
|
140
|
+
end
|
141
|
+
|
142
|
+
def reset_inheritable_attributes
|
143
|
+
@inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
|
144
|
+
end
|
145
|
+
private
|
146
|
+
|
147
|
+
# Prevent this constant from being created multiple times
|
148
|
+
EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze unless const_defined?(:EMPTY_INHERITABLE_ATTRIBUTES)
|
149
|
+
|
150
|
+
def inherited_with_inheritable_attributes(child)
|
151
|
+
inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
|
152
|
+
|
153
|
+
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
|
154
|
+
new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
|
155
|
+
else
|
156
|
+
new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
|
157
|
+
memo.update(key => value.duplicable? ? value.dup : value)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
include ClassExtensions
|
166
|
+
alias inherited_without_inheritable_attributes inherited
|
167
|
+
alias inherited inherited_with_inheritable_attributes
|
168
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Object
|
2
|
+
# Can you safely .dup this object?
|
3
|
+
# False for nil, false, true, symbols, and numbers; true otherwise.
|
4
|
+
def duplicable?
|
5
|
+
true
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class NilClass #:nodoc:
|
10
|
+
def duplicable?
|
11
|
+
false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class FalseClass #:nodoc:
|
16
|
+
def duplicable?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class TrueClass #:nodoc:
|
22
|
+
def duplicable?
|
23
|
+
false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Symbol #:nodoc:
|
28
|
+
def duplicable?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Numeric #:nodoc:
|
34
|
+
def duplicable?
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class File
|
2
|
+
module FileExtensions
|
3
|
+
module ClassMethods
|
4
|
+
def mkfifo(name, mode="666", open_mode="r")
|
5
|
+
# XXX not used
|
6
|
+
if File.exists? name and File.pipe? name # Leftover from before
|
7
|
+
File.delete name
|
8
|
+
end
|
9
|
+
|
10
|
+
# apalling, but ruby/dl has x-p problems
|
11
|
+
if ! File.exists? name
|
12
|
+
`mkfifo -m #{ mode } #{ name }`
|
13
|
+
end
|
14
|
+
|
15
|
+
return File.open(name, open_mode)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.included(klass)
|
20
|
+
klass.extend(ClassMethods)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
include FileExtensions
|
24
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Fixnum
|
2
|
+
module FixnumExtensions
|
3
|
+
# Ridiculous that this isn't in the library.
|
4
|
+
def printable?; self >= 0x20 and self <= 0x7e; end
|
5
|
+
|
6
|
+
# Like Numeric#Step, but yields the length of each span along with
|
7
|
+
# the offset. Useful for stepping through data in increments:
|
8
|
+
# 0.stepwith(buffer.size, 4096) {|off,len| pp buffer[off,len]}
|
9
|
+
# The "len" parameter accounts for the inevitable short final block.
|
10
|
+
def stepwith(limit, stepv, &block)
|
11
|
+
# XXX not used
|
12
|
+
step(limit, stepv) do |i|
|
13
|
+
remt = limit - i
|
14
|
+
yield i, remt.cap(stepv)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# you can't clone a fixnum? Why?
|
19
|
+
def clone; self; end
|
20
|
+
|
21
|
+
def upper?; self >= 0x41 and self <= 0x5a; end
|
22
|
+
def lower?; self >= 0x61 and self <= 0x7a; end
|
23
|
+
end
|
24
|
+
include FixnumExtensions
|
25
|
+
end
|
26
|
+
|