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.
Files changed (59) hide show
  1. data/.document +5 -0
  2. data/.gitignore +22 -0
  3. data/README +0 -0
  4. data/README.markdown +51 -0
  5. data/Rakefile +54 -0
  6. data/VERSION +1 -0
  7. data/lib/ruckus.rb +70 -0
  8. data/lib/ruckus/blob.rb +113 -0
  9. data/lib/ruckus/choice.rb +55 -0
  10. data/lib/ruckus/dfuzz.rb +231 -0
  11. data/lib/ruckus/dictionary.rb +119 -0
  12. data/lib/ruckus/enum.rb +39 -0
  13. data/lib/ruckus/extensions/array.rb +33 -0
  14. data/lib/ruckus/extensions/class.rb +168 -0
  15. data/lib/ruckus/extensions/duplicable.rb +37 -0
  16. data/lib/ruckus/extensions/file.rb +24 -0
  17. data/lib/ruckus/extensions/fixnum.rb +26 -0
  18. data/lib/ruckus/extensions/hash.rb +10 -0
  19. data/lib/ruckus/extensions/integer.rb +26 -0
  20. data/lib/ruckus/extensions/ipaddr.rb +155 -0
  21. data/lib/ruckus/extensions/irb.rb +30 -0
  22. data/lib/ruckus/extensions/math.rb +6 -0
  23. data/lib/ruckus/extensions/module.rb +37 -0
  24. data/lib/ruckus/extensions/numeric.rb +117 -0
  25. data/lib/ruckus/extensions/object.rb +22 -0
  26. data/lib/ruckus/extensions/range.rb +16 -0
  27. data/lib/ruckus/extensions/socket.rb +20 -0
  28. data/lib/ruckus/extensions/string.rb +327 -0
  29. data/lib/ruckus/filter.rb +16 -0
  30. data/lib/ruckus/human_display.rb +79 -0
  31. data/lib/ruckus/ip.rb +38 -0
  32. data/lib/ruckus/mac_addr.rb +31 -0
  33. data/lib/ruckus/mutator.rb +318 -0
  34. data/lib/ruckus/null.rb +24 -0
  35. data/lib/ruckus/number.rb +360 -0
  36. data/lib/ruckus/parsel.rb +363 -0
  37. data/lib/ruckus/selector.rb +92 -0
  38. data/lib/ruckus/str.rb +164 -0
  39. data/lib/ruckus/structure.rb +263 -0
  40. data/lib/ruckus/structure/atcreate.rb +23 -0
  41. data/lib/ruckus/structure/beforebacks.rb +28 -0
  42. data/lib/ruckus/structure/defaults.rb +57 -0
  43. data/lib/ruckus/structure/factory.rb +42 -0
  44. data/lib/ruckus/structure/fixupfields.rb +16 -0
  45. data/lib/ruckus/structure/initializers.rb +14 -0
  46. data/lib/ruckus/structure/relate.rb +34 -0
  47. data/lib/ruckus/structure/replacement.rb +30 -0
  48. data/lib/ruckus/structure/searchmods.rb +33 -0
  49. data/lib/ruckus/structure/structureproxies.rb +28 -0
  50. data/lib/ruckus/structure/validate.rb +12 -0
  51. data/lib/ruckus/structure_shortcuts.rb +109 -0
  52. data/lib/ruckus/time_t.rb +26 -0
  53. data/lib/ruckus/vector.rb +97 -0
  54. data/ruckus.gemspec +104 -0
  55. data/test/test_decides.rb +61 -0
  56. data/test/test_mutator.rb +29 -0
  57. data/test/test_override.rb +23 -0
  58. data/test/test_replace.rb +39 -0
  59. 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
@@ -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
+