primitive_wrapper 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +113 -18
- data/lib/primitive_wrapper.rb +486 -5
- data/lib/primitive_wrapper/version.rb +1 -1
- data/primitive_wrapper.gemspec +5 -1
- metadata +49 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e2d245c1ee0f7d46c0df391fcd4165fe22095f9
|
4
|
+
data.tar.gz: b7e8d55707e1b244619154de8373a473e364278c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d8791c319f2209cd5bc85dbca416b5471a751a316ad814370cc967e9f5e9f94dd9b2a4d7143a3a92d06ba8f973fbf97e7ef5d35943bbcdba5436b3f9a98d896
|
7
|
+
data.tar.gz: 079ed7917773ad0f916afca375fbddf0285328abda5691cd44cfcaa5b0eedcc786f2158a61bf876a6e6b6b5f5fff4e0818a7c0425ae8bb5f77cda5f62b14da80
|
data/README.md
CHANGED
@@ -65,21 +65,31 @@ five.kind_of? Integer # false
|
|
65
65
|
five.kind_of? Value # true
|
66
66
|
|
67
67
|
5.kind_of? Integer # true
|
68
|
-
5.kind_of? Value # false
|
68
|
+
5.kind_of? Value # false
|
69
|
+
|
70
|
+
five.type_of? Integer # true
|
71
|
+
5.type_of? Integer # true
|
69
72
|
```
|
70
73
|
|
71
74
|
As we can see from the above code, the Int class does not derive from Integer or anything that would appear numeric.
|
72
75
|
Our `Int` class is simply a container which happens to have the methods of `Integer` but does not derive itself from `Integer`.
|
73
76
|
All of these container objects derive from the Value class.
|
77
|
+
Also note the new method `#type_of` which allows us test the inner-most entity.
|
74
78
|
|
75
79
|
#### Object methods added
|
76
80
|
|
77
|
-
There are
|
81
|
+
There are five new instance methods added to the base Object class necessary to implement this system.
|
78
82
|
The most important method is the `#to_wrapper` method.
|
79
83
|
When an instance variable calls this method, one of the wrapper containers will generate a new instance.
|
80
84
|
The one that gets picked is the one best suited for usability.
|
81
|
-
|
82
|
-
|
85
|
+
We also have a test method called `#wrapped?` to see if we are dealing with the original entity or its thinly wrapped sibling.
|
86
|
+
Another method named `#prim_value` will return the inner container value or simply return `self` if it is not a container derived from the `Value` class.
|
87
|
+
This is mostly used internally by the container objects. Now that we have wrapped versions of the base elemental objects,
|
88
|
+
we need a type checking method that can work on both wrapped and unwrapped primitives: called `#type_of?`.
|
89
|
+
Also needed is a method that can duplicated a primitive or its wrapped version; this is called `#pw_copy` which works like dup.
|
90
|
+
Note that you can't call `#dup` on an Integer without raising an exception.
|
91
|
+
|
92
|
+
Below shows which objects get mapped to which containers:
|
83
93
|
|
84
94
|
```
|
85
95
|
nil => Bit
|
@@ -91,20 +101,24 @@ Rational => Number
|
|
91
101
|
Symbol => SymbolW
|
92
102
|
Hash => Property
|
93
103
|
String => Datum
|
104
|
+
Array => XArray
|
105
|
+
Range => XRange
|
94
106
|
```
|
95
107
|
|
96
108
|
Some examples are as follows:
|
97
109
|
|
98
110
|
```ruby
|
99
|
-
n = nil.to_wrapper
|
100
|
-
b = true.to_wrapper
|
101
|
-
y = 13.to_wrapper
|
102
|
-
t = 3e-9.to_wrapper
|
103
|
-
z = (1+6i).to_wrapper
|
104
|
-
str = "yo!".to_wrapper
|
105
|
-
me = :me.to_wrapper
|
106
|
-
prop = {}.to_wrapper
|
107
|
-
|
111
|
+
n = nil.to_wrapper # n.class == Bit
|
112
|
+
b = true.to_wrapper # b.class == Bool
|
113
|
+
y = 13.to_wrapper # y.class == Int
|
114
|
+
t = 3e-9.to_wrapper # t.class == FloatW
|
115
|
+
z = (1+6i).to_wrapper # z.class == Number
|
116
|
+
str = "yo!".to_wrapper # str.class == Datum
|
117
|
+
me = :me.to_wrapper # me.class == SymbolW
|
118
|
+
prop = {}.to_wrapper # prop.class == Property
|
119
|
+
ary = [1,2].to_wrapper # ary.class == XArray ... X for extended functionality
|
120
|
+
ran = (3..0).to_wrapper # ran.class == XRange
|
121
|
+
aw = /[az]/.to_wrapper # aw.class == Value ... everything else goes inside the Value container
|
108
122
|
```
|
109
123
|
|
110
124
|
The next sections will detail which objects are allowed to be contained within each container objects.
|
@@ -112,12 +126,11 @@ The next sections will detail which objects are allowed to be contained within e
|
|
112
126
|
#### Value class container
|
113
127
|
|
114
128
|
This is the base class for all the containers created by this gem. Any object or primitive type can be held in this container.
|
115
|
-
To access the contents, simply call `#val`, `#prim_val`, or
|
129
|
+
To access the contents, simply call `#val`, `#prim_val`, `#unwrap`, or for non-numeric types use the tilde `~` prefix operator.
|
116
130
|
Note that only `Value` derived objects can call `#val` while every object can call `#prim_val`.
|
117
131
|
You can also replace the contents with the `#replace` method or the `#val=` method.
|
118
132
|
The `Value` container has no restrictions on what it can hold. Other wrappers will raise an exception if the wrong type is added.
|
119
133
|
The comparison binary operators `==`, and `!=` are used to compare equality and inequality; this is done on the inner contained element.
|
120
|
-
Note that arrays are already containers, so there is little utility in placing it in another container.
|
121
134
|
The value container can only contain a single object; it is like an Array object that is only allowed to hold one item.
|
122
135
|
See the example code below:
|
123
136
|
|
@@ -153,7 +166,11 @@ The Value class has the following instance methods:
|
|
153
166
|
:== # Compares equality of the inner elements
|
154
167
|
:!= # Compares inequality of the inner elements
|
155
168
|
:inspect # "(Value)==>data" where Value is the class name of the Value derived object, and data is #val.inspect
|
156
|
-
:to_s # returns #to_s on contained entity
|
169
|
+
:to_s # returns #to_s on contained entity
|
170
|
+
:to_wrapper # returns self ... prevents wrapping a wrapped entity
|
171
|
+
:wrapped? # also on object, tests for wrapped behavior
|
172
|
+
:type_of? # also added to object, tests innermost entity or self if primitive
|
173
|
+
:inspect # string representing wrapped primitive
|
157
174
|
```
|
158
175
|
|
159
176
|
#### Bool class container
|
@@ -227,6 +244,8 @@ The `#to_int` method on `Int` returns self, while `#to_i` accesses the primitive
|
|
227
244
|
Most of the time if `Integer` does not recognize something it calls coerce on the foreign object (which we grabbed from Integer).
|
228
245
|
This means that most expressions should work in whatever order you wish: if not, you will have to convert the Int object into an Integer object.
|
229
246
|
Pretty much all expressions with Int will create a primitive Integer.
|
247
|
+
We also have new methods `#inc` and `#dec` which work like the `C/C++` post increment operators.
|
248
|
+
Prefix version methods are `#pre_inc` and `#pre_dec`.
|
230
249
|
See the example below:
|
231
250
|
|
232
251
|
```ruby
|
@@ -289,13 +308,13 @@ See below:
|
|
289
308
|
|
290
309
|
```ruby
|
291
310
|
# non-mutating methods taken from Symbol:
|
292
|
-
# :<, :<=, :>, :>=, :[], :between?, :capitalize, :downcase, :empty?, :length, :next, :size, :succ, :swapcase, :upcase
|
311
|
+
# :<, :<=, :>, :>=, :[], :between?, :capitalize, :downcase, :empty?, :length, :next, :size, :succ, :pred, :swapcase, :upcase
|
293
312
|
|
294
313
|
# non-mutating methods taken from String:
|
295
314
|
# :append, :include?, :prepend ... actually append renamed from :<<
|
296
315
|
|
297
316
|
# mutating methods of SymbolW
|
298
|
-
# :[]=, :append!, :capitalize!, :downcase!, :next!, :prepend!, :replace, :succ!, :swapcase!, :upcase!
|
317
|
+
# :[]=, :append!, :capitalize!, :downcase!, :next!, :prepend!, :replace, :succ!, :pred!, :swapcase!, :upcase!
|
299
318
|
|
300
319
|
# construction:
|
301
320
|
wsym = :my_symbol.to_wrapper
|
@@ -379,6 +398,74 @@ abc.defined_properties! # [] ... you just zapped the entire hash after abc
|
|
379
398
|
# ::reserve_property_names! [] ... adds additional reserved words
|
380
399
|
```
|
381
400
|
|
401
|
+
#### XRange class container for Range with extensions
|
402
|
+
|
403
|
+
While inheritance could have accomplished similar goals, this gem is all about wrapped objects.
|
404
|
+
Mutability would not be possible with an inherited version. Note that Range objects are not completely immutable;
|
405
|
+
`range_instance.first.upcase!` will modify the range that is defined with strings.
|
406
|
+
The `XRange` object redefines much of the behavior of `Range` with regard to ranges that descend rather than ascend.
|
407
|
+
Note that descending Range objects will return false on methods such as `#include?` and `#cover?` and will not enumerate with `#each`.
|
408
|
+
There is great utility in having a functional downward range that actually does what would naturally be expected.
|
409
|
+
This gem includes the gem `pred` which makes reverse behavior possible.
|
410
|
+
Integers and Strings use the method `#succ` within the classic `Range` to get the next sequence value.
|
411
|
+
The method `#pred` is added to to Integers and Strings to get the inverse sequence value.
|
412
|
+
The `XRange` container captures the methods of `Range` but redefines most of the methods to define reverse behavior.
|
413
|
+
Below is a list of what has changed:
|
414
|
+
|
415
|
+
```ruby
|
416
|
+
# :reverse Range, XRange ... reverses first and last, creates a new object of same type as caller
|
417
|
+
# :reverse! XRange ... self-modified version of :reverse
|
418
|
+
# :reverse? Range, XRange ... true if descending
|
419
|
+
# :simplify Range, XRange ... converts if possible excluded to non-excluded range with same behavior
|
420
|
+
# :simplefy! XRange ... self-modified version of :simplify
|
421
|
+
# :reorder Range, XRange ... creates ascending Range or XRange
|
422
|
+
# :reorder! XRange ... self-modified version of :reorder
|
423
|
+
# :to_range Range, XRange ... accesses inner element or returns self if Range
|
424
|
+
# :to_xr Range, XRange ... creates an XRange object or returns self if XRange
|
425
|
+
# :size, :count XRange ... redefined from nil to actual size if descending were reversed
|
426
|
+
# :include? XRange ... redefined from false to behave as if reversed
|
427
|
+
# :cover? XRange ... redefined from false to behave as if reversed
|
428
|
+
# :member? XRange ... redefined from false to behave as if reversed
|
429
|
+
# :to_a XRange ... redefined from empty [] to list ordered sequence
|
430
|
+
# :max, :min XRange ... redefined from nil to return maximum/minimum range values
|
431
|
+
# :eql? :== XRange ... compares using contained entity
|
432
|
+
# :step(n) XRange ... redefined to work with descending sequences
|
433
|
+
# :reverse_step(n) XRange ... reverses sequence before stepping
|
434
|
+
# :each XRange ... redefined to work with descending sequences
|
435
|
+
# :reverse_each XRange ... reverse version of :each
|
436
|
+
# :re_range(ng) XRange ... creates new range converting negative start, end to positive given size==ng
|
437
|
+
# ... used by XArray access operators that use descending ranges.
|
438
|
+
```
|
439
|
+
|
440
|
+
#### XArray class container for Array with extensions
|
441
|
+
|
442
|
+
This creates a wrapped `Array` with behavior that enhances the access operators of `Array`;
|
443
|
+
additionally a few new methods were added to the wrapped version.
|
444
|
+
The methods `#ssort`, `#ssort!` sort `XArray` elements using `#to_s` on each comparison.
|
445
|
+
The methods `#isort`, `#isort!` sort `XArray` elements using `#inspect` on each comparison.
|
446
|
+
The method `#to_xa` what added to `Array` as a more terse way of creating a wrapper on `Array`.
|
447
|
+
The method `#empty!` was also added. These two aforementioned methods also get included in `XArray`.
|
448
|
+
`XArray` mimics the behavior of `Array` but redefines `:[]` and `:[]=` to include lists wich comprise indexes, ranges, and arrays of indexes.
|
449
|
+
There is also behavior that defines many-to-one, one-to-many, and many-to-many operations. Note that one-to-one behavior has not changed.
|
450
|
+
An example best explains how this works:
|
451
|
+
|
452
|
+
```ruby
|
453
|
+
ary = [2,3,5,7,11,13,17,19,23,29,31,37,41].to_xa
|
454
|
+
tst = ary[5..0,10,-1] # tst == [13, 11, 7, 5, 3, 2, 31, 41] ... note reverse range
|
455
|
+
|
456
|
+
# many-to-many
|
457
|
+
ary[4,5,1] = "a", "b", "c", "d" # ary == [2, "c", 5, 7, "a", "b", 17, 19, 23, 29, 31, 37, 41]
|
458
|
+
# note above, unused ignored
|
459
|
+
|
460
|
+
# one-to-many
|
461
|
+
ary[8..-1] = :s # ary == [2, 3, 5, 7, 11, 13, 17, 19, :s, :s, :s, :s, :s]
|
462
|
+
# note: ary.prim_value[8..-1] = :s returns this: [2, 3, 5, 7, 11, 13, 17, 19, :s] ... which is useless
|
463
|
+
|
464
|
+
# many-to-one
|
465
|
+
ary[-1] = 1,2,3 # ary == [2, "c", 5, 7, "a", "b", 17, 19, :s, :s, :s, :s, [1, 2, 3]]
|
466
|
+
ary[-2] = [:a, :b] # ary == [2, "c", 5, 7, "a", "b", 17, 19, :s, :s, :s, [:a, :b], [1, 2, 3]]
|
467
|
+
```
|
468
|
+
|
382
469
|
#### Customization
|
383
470
|
|
384
471
|
Things should work out of the box, until they don't. This section will detail what customization is possible with what container.
|
@@ -475,6 +562,14 @@ Now we are left with the head-scratcher on how to decide which is the best retur
|
|
475
562
|
This can be mostly a matter of taste, but we can choose custom names that convey this information. Now if you have an extension library such as used by the `gstring` gem, you have an even larger list to choose from.
|
476
563
|
So it is left to you to decide.
|
477
564
|
|
565
|
+
## Revision History
|
566
|
+
### Version 1.0.0
|
567
|
+
* fixed wrapper inside wrapper causing stack overflow
|
568
|
+
* Documentation updates
|
569
|
+
* Added new wrappers for Range, Array as XRange and XArray
|
570
|
+
* added primitive methods
|
571
|
+
* added Value methods, and enhanced other derived wrappers
|
572
|
+
|
478
573
|
## Development
|
479
574
|
|
480
575
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/primitive_wrapper.rb
CHANGED
@@ -1,14 +1,24 @@
|
|
1
1
|
require "primitive_wrapper/version"
|
2
2
|
require "blockify"
|
3
|
-
|
3
|
+
require "yieldhelper" # am I using this really?
|
4
|
+
require "pred"
|
4
5
|
|
5
6
|
#
|
6
7
|
# Standard Object upgrades
|
7
8
|
#
|
8
9
|
class Object
|
10
|
+
def type_of?(cls)
|
11
|
+
kind_of? cls
|
12
|
+
end
|
13
|
+
def pw_copy
|
14
|
+
self.dup rescue self
|
15
|
+
end
|
9
16
|
def prim_value
|
10
17
|
self
|
11
18
|
end
|
19
|
+
def wrapped?
|
20
|
+
false
|
21
|
+
end
|
12
22
|
def to_wrapper
|
13
23
|
return Bit.new(nil) if self.nil?
|
14
24
|
return Bool.new(true) if self==true
|
@@ -19,6 +29,8 @@ class Object
|
|
19
29
|
return Datum.new(self) if self.kind_of? String
|
20
30
|
return SymbolW.new(self) if self.kind_of? Symbol
|
21
31
|
return Property.new(self) if self.kind_of? Hash
|
32
|
+
return XArray.new(self) if self.kind_of? Array
|
33
|
+
return XRange.new(self) if self.kind_of? Range
|
22
34
|
return Value.new(self)
|
23
35
|
end
|
24
36
|
end
|
@@ -47,6 +59,62 @@ class NilClass
|
|
47
59
|
end
|
48
60
|
end
|
49
61
|
|
62
|
+
class Range
|
63
|
+
def ~
|
64
|
+
self
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Array
|
69
|
+
def ~
|
70
|
+
self
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Range # if it makes sense, add methods here
|
75
|
+
def reversed?
|
76
|
+
first > last
|
77
|
+
end
|
78
|
+
def to_xr
|
79
|
+
XRange.new self
|
80
|
+
end
|
81
|
+
def reverse
|
82
|
+
if exclude_end?
|
83
|
+
(last...first)
|
84
|
+
else
|
85
|
+
(last..first)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
def reorder
|
89
|
+
if exclude_end?
|
90
|
+
last < first ? (last...first) : (first...last)
|
91
|
+
else
|
92
|
+
last < first ? (last..first) : (first..last)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
def reversed?
|
96
|
+
last < first
|
97
|
+
end
|
98
|
+
def simplify
|
99
|
+
if exclude_end?
|
100
|
+
return (first...last) if first==last
|
101
|
+
return (first..last.pred)
|
102
|
+
end
|
103
|
+
return (first..last)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class Array
|
108
|
+
def empty!
|
109
|
+
old = self.dup
|
110
|
+
replace []
|
111
|
+
return old
|
112
|
+
end
|
113
|
+
def to_xa
|
114
|
+
XArray.new(self)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
50
118
|
#
|
51
119
|
# BASE CLASS == Value ... a wrapper for any ruby object
|
52
120
|
#
|
@@ -68,6 +136,18 @@ class Value
|
|
68
136
|
@value = obj
|
69
137
|
end
|
70
138
|
|
139
|
+
def to_wrapper
|
140
|
+
self
|
141
|
+
end
|
142
|
+
def wrapped?
|
143
|
+
true
|
144
|
+
end
|
145
|
+
def type_of?(cls)
|
146
|
+
return true if @value.kind_of? cls
|
147
|
+
return true if self.kind_of? cls
|
148
|
+
false
|
149
|
+
end
|
150
|
+
|
71
151
|
def ensure_valid(obj, mess = "Incompatible type")
|
72
152
|
unless valid_type(obj)
|
73
153
|
raise mess
|
@@ -111,7 +191,7 @@ class Value
|
|
111
191
|
end
|
112
192
|
|
113
193
|
def replace(other)
|
114
|
-
@value = other if valid_type(other)
|
194
|
+
@value = other.prim_value if valid_type(other)
|
115
195
|
end
|
116
196
|
|
117
197
|
def to_s
|
@@ -307,10 +387,10 @@ class SymbolW < Value
|
|
307
387
|
end
|
308
388
|
|
309
389
|
# create non-mutate SymbolW methods
|
310
|
-
bestow_symbol_methods( [:next, :succ, :[], :length, :size, :upcase, :downcase, :capitalize, :swapcase, :<, :>, :<=, :>=, :between?, :empty? ], false)
|
390
|
+
bestow_symbol_methods( [:next, :succ, :pred, :[], :length, :size, :upcase, :downcase, :capitalize, :swapcase, :<, :>, :<=, :>=, :between?, :empty? ], false)
|
311
391
|
|
312
392
|
# create mutate SymbolW methods ... these will auto-bang!
|
313
|
-
bestow_symbol_methods([:next, :succ, :upcase, :downcase, :capitalize, :swapcase, :
|
393
|
+
bestow_symbol_methods([:next, :succ, :upcase, :downcase, :capitalize, :swapcase, :pred], true)
|
314
394
|
|
315
395
|
# string non-mutate methods
|
316
396
|
bestow_string_non_mutate_methods([:match, :include?], nil)
|
@@ -375,6 +455,14 @@ class Int < ValueAdd
|
|
375
455
|
def ~
|
376
456
|
~@value
|
377
457
|
end
|
458
|
+
|
459
|
+
def pre_inc
|
460
|
+
@value+=1
|
461
|
+
end
|
462
|
+
|
463
|
+
def pre_dec
|
464
|
+
@value-=1
|
465
|
+
end
|
378
466
|
end
|
379
467
|
|
380
468
|
class FloatW < ValueAdd
|
@@ -539,7 +627,7 @@ class Property < Value
|
|
539
627
|
@hold_keys.each_pair do |key,val|
|
540
628
|
bad[key] = @value[key]
|
541
629
|
end
|
542
|
-
return [good,bad]
|
630
|
+
return [good, bad]
|
543
631
|
end
|
544
632
|
|
545
633
|
def [](idx)
|
@@ -604,7 +692,400 @@ class Property < Value
|
|
604
692
|
@value[key]=dflt
|
605
693
|
end
|
606
694
|
end
|
695
|
+
end
|
607
696
|
|
697
|
+
class XRange < ValueAdd
|
698
|
+
capture_base_methods(Range)
|
699
|
+
def valid_type(prm)
|
700
|
+
return true if prm.kind_of? Range
|
701
|
+
return true if prm.kind_of? XRange
|
702
|
+
false
|
703
|
+
end
|
704
|
+
def reverse!
|
705
|
+
@value = @value.reverse
|
706
|
+
self
|
707
|
+
end
|
708
|
+
def reverse
|
709
|
+
@value.reverse.to_xr
|
710
|
+
end
|
711
|
+
def simplify!
|
712
|
+
@value = @value.simplify
|
713
|
+
self
|
714
|
+
end
|
715
|
+
def reorder!
|
716
|
+
@value = @value.reorder
|
717
|
+
self
|
718
|
+
end
|
719
|
+
|
720
|
+
def simplify
|
721
|
+
@value.simplify.to_xr
|
722
|
+
end
|
723
|
+
def to_xr
|
724
|
+
self
|
725
|
+
end
|
726
|
+
def to_range # add similar to other wrappers
|
727
|
+
@value
|
728
|
+
end
|
729
|
+
def re_range(ng)
|
730
|
+
return self if ng.nil?
|
731
|
+
return self if ng <= 0
|
732
|
+
return self unless first.kind_of? Integer
|
733
|
+
t_first = first
|
734
|
+
t_last = last
|
735
|
+
if first.negative?
|
736
|
+
t_first = ng+first
|
737
|
+
end
|
738
|
+
if last.negative?
|
739
|
+
t_last = ng+last
|
740
|
+
end
|
741
|
+
if exclude_end?
|
742
|
+
XRange.new (t_first...t_last)
|
743
|
+
else
|
744
|
+
XRange.new (t_first..t_last)
|
745
|
+
end
|
746
|
+
end
|
747
|
+
def re_range!(ng)
|
748
|
+
replace re_range(ng)
|
749
|
+
end
|
750
|
+
def size # getting the wrong count ... off by 1
|
751
|
+
dirty = false
|
752
|
+
sz = @value.size
|
753
|
+
if sz.nil?
|
754
|
+
dirty = true
|
755
|
+
elsif sz==0
|
756
|
+
dirty = true
|
757
|
+
end
|
758
|
+
unless dirty
|
759
|
+
return sz
|
760
|
+
end
|
761
|
+
if first.respond_to? :lcm # Covers both Integer and Int
|
762
|
+
sz = reversed? ? @value.reverse.size : @value.size
|
763
|
+
return sz
|
764
|
+
end
|
765
|
+
range = @value.reorder
|
766
|
+
cnt = 0
|
767
|
+
# curr = range.first.dup rescue range.first
|
768
|
+
curr = range.first.pw_copy
|
769
|
+
stop = range.last
|
770
|
+
loop do
|
771
|
+
cnt += 1 # 5..5 is count of 1
|
772
|
+
break if curr==stop
|
773
|
+
curr.succ!
|
774
|
+
end
|
775
|
+
cnt -= 1 if exclude_end?
|
776
|
+
return cnt
|
777
|
+
end
|
778
|
+
def count
|
779
|
+
size
|
780
|
+
end
|
781
|
+
def include?(val) # account for reversed ordering
|
782
|
+
@value.reorder.include? val
|
783
|
+
end
|
784
|
+
def cover?(val) # means val>=start and val<=end ... different than include
|
785
|
+
@value.reorder.include? val
|
786
|
+
end
|
787
|
+
def member?(val) # same as include?
|
788
|
+
@value.reorder.include? val
|
789
|
+
end
|
790
|
+
def to_a
|
791
|
+
dat = @value.reorder.to_a
|
792
|
+
return reversed? ? dat.reverse : dat
|
793
|
+
end
|
794
|
+
def max(*n, &block)
|
795
|
+
@value.reorder.send(:max, *n, &block)
|
796
|
+
end
|
797
|
+
def min(*n, &block)
|
798
|
+
@value.reorder.send(:min, *n, &block)
|
799
|
+
end
|
800
|
+
def eql?
|
801
|
+
@value.eql? (~other)
|
802
|
+
end
|
803
|
+
def ===(other)
|
804
|
+
@value.include? other
|
805
|
+
end
|
806
|
+
|
807
|
+
def ==(other)
|
808
|
+
@value.eql? (~other)
|
809
|
+
end
|
810
|
+
|
811
|
+
def step(n=1)
|
812
|
+
n = 1 if n<= 0
|
813
|
+
return Enumerator.enumerate_yields(self, :step, n) unless block_given?
|
814
|
+
curr = first.pw_copy
|
815
|
+
if exclude_end?
|
816
|
+
if reversed?
|
817
|
+
loop do
|
818
|
+
break if curr <= last
|
819
|
+
yield curr
|
820
|
+
n.times { |t| curr = curr.pred }
|
821
|
+
end
|
822
|
+
else
|
823
|
+
loop do
|
824
|
+
break if curr >= last
|
825
|
+
yield curr
|
826
|
+
n.times { |t| curr = curr.succ }
|
827
|
+
end
|
828
|
+
end
|
829
|
+
else
|
830
|
+
if reversed?
|
831
|
+
loop do
|
832
|
+
yield curr
|
833
|
+
break if curr <= last
|
834
|
+
n.times { |t| curr = curr.pred }
|
835
|
+
end
|
836
|
+
else
|
837
|
+
loop do
|
838
|
+
yield curr
|
839
|
+
break if curr >= last
|
840
|
+
n.times { |t| curr = curr.succ }
|
841
|
+
end
|
842
|
+
end
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
def reverse_step(n=1)
|
847
|
+
n = 1 if n<= 0
|
848
|
+
return Enumerator.enumerate_yields(self, :reverse_step, n) unless block_given?
|
849
|
+
curr = last.pw_copy
|
850
|
+
if exclude_end?
|
851
|
+
if reversed?
|
852
|
+
loop do
|
853
|
+
break if curr >= first
|
854
|
+
yield curr
|
855
|
+
n.times { |t| curr = curr.succ }
|
856
|
+
end
|
857
|
+
else
|
858
|
+
loop do
|
859
|
+
break if curr <= first
|
860
|
+
yield curr
|
861
|
+
n.times { |t| curr = curr.pred }
|
862
|
+
end
|
863
|
+
end
|
864
|
+
else
|
865
|
+
if reversed?
|
866
|
+
loop do
|
867
|
+
yield curr
|
868
|
+
break if curr >= first
|
869
|
+
n.times { |t| curr = curr.succ }
|
870
|
+
end
|
871
|
+
else
|
872
|
+
loop do
|
873
|
+
yield curr
|
874
|
+
break if curr <= first
|
875
|
+
n.times { |t| curr = curr.pred }
|
876
|
+
end
|
877
|
+
end
|
878
|
+
end
|
879
|
+
end
|
880
|
+
|
881
|
+
def each(&block)
|
882
|
+
self.send(:step, 1, &block)
|
883
|
+
end
|
884
|
+
|
885
|
+
def reverse_each(&block)
|
886
|
+
self.send(:reverse_step, 1, &block)
|
887
|
+
end
|
888
|
+
|
889
|
+
end
|
890
|
+
|
891
|
+
module PrimitiveWrapper
|
892
|
+
def self.get_list(list, ng=nil)
|
893
|
+
rtn = []
|
894
|
+
if list.empty?
|
895
|
+
return []
|
896
|
+
elsif list.count == 1
|
897
|
+
item = list.first
|
898
|
+
if item.type_of? Range
|
899
|
+
rtn.push item.to_wrapper
|
900
|
+
else
|
901
|
+
rtn.push item
|
902
|
+
end
|
903
|
+
return rtn
|
904
|
+
end
|
905
|
+
list.each do |ii|
|
906
|
+
if(ii.type_of? Range)
|
907
|
+
ii = ii.to_wrapper
|
908
|
+
ii.re_range!(ng)
|
909
|
+
end
|
910
|
+
if ((ii.type_of? Range) || (ii.type_of? Array))
|
911
|
+
ii.each do |idx|
|
912
|
+
rtn.push idx
|
913
|
+
end
|
914
|
+
else
|
915
|
+
rtn.push ii
|
916
|
+
end
|
917
|
+
end
|
918
|
+
return rtn
|
919
|
+
end
|
920
|
+
def self.copy(dest, source, indexes)
|
921
|
+
rtn = []
|
922
|
+
if indexes == :all
|
923
|
+
if source.type_of? Array
|
924
|
+
source.count.times do |idx|
|
925
|
+
rtn.push(dest[idx]=source[idx])
|
926
|
+
end
|
927
|
+
else
|
928
|
+
dest.count.times do |idx|
|
929
|
+
rtn.push(dest[idx]=source)
|
930
|
+
end
|
931
|
+
end
|
932
|
+
else
|
933
|
+
if source.type_of? Array
|
934
|
+
ii = 0
|
935
|
+
indexes.each do |idx|
|
936
|
+
rtn.push(dest[idx]=source[ii])
|
937
|
+
ii += 1
|
938
|
+
end
|
939
|
+
else
|
940
|
+
indexes.each do |idx|
|
941
|
+
rtn.push(dest[idx]=source)
|
942
|
+
end
|
943
|
+
end
|
944
|
+
end
|
945
|
+
rtn.count <= 1 ? rtn.first : rtn
|
946
|
+
end
|
608
947
|
end
|
609
948
|
|
610
949
|
|
950
|
+
### need to figure out how left and right things work ...
|
951
|
+
####
|
952
|
+
### OK this is cool, things on the right if more than one go in one array
|
953
|
+
### ... or a non-array if just one item
|
954
|
+
|
955
|
+
class XArray < ValueAdd
|
956
|
+
LAM_ISORT = lambda {|a,b| a.inspect <=> b.inspect }
|
957
|
+
LAM_SSORT = lambda {|a,b| a.to_s <=> b.to_s }
|
958
|
+
capture_base_methods(Array)
|
959
|
+
|
960
|
+
def initialize(obj=[])
|
961
|
+
obj = obj.prim_value
|
962
|
+
ensure_valid(obj)
|
963
|
+
@value = obj
|
964
|
+
end
|
965
|
+
|
966
|
+
def valid_type(prm)
|
967
|
+
return true if prm.kind_of? Array
|
968
|
+
return true if prm.kind_of? XArray
|
969
|
+
false
|
970
|
+
end
|
971
|
+
def isort
|
972
|
+
@value.sort &LAM_ISORT
|
973
|
+
end
|
974
|
+
def isort!
|
975
|
+
@value.sort! &LAM_ISORT
|
976
|
+
end
|
977
|
+
def ssort
|
978
|
+
@value.sort &LAM_SSORT
|
979
|
+
end
|
980
|
+
def ssort!
|
981
|
+
@value.sort! &LAM_SSORT
|
982
|
+
end
|
983
|
+
def [](*list)
|
984
|
+
list = PrimitiveWrapper::get_list(list,size)
|
985
|
+
if list.empty?
|
986
|
+
return nil
|
987
|
+
elsif list.count==1
|
988
|
+
if list.first == :all
|
989
|
+
return @value
|
990
|
+
elsif list.first.type_of? Range # get_list may pick this appart
|
991
|
+
rtn = []
|
992
|
+
list.first.to_wrapper.re_range(size).each do |idx|
|
993
|
+
rtn.push @value[idx]
|
994
|
+
end
|
995
|
+
return rtn
|
996
|
+
else
|
997
|
+
return @value[list.first]
|
998
|
+
end
|
999
|
+
end
|
1000
|
+
rtn = []
|
1001
|
+
# for now keep this here until you can justify that it is not needed
|
1002
|
+
list.each do |ii| # I don't need to do this do I ??? get_list should untangle things
|
1003
|
+
if ii.type_of? Range
|
1004
|
+
ii.to_wrapper.re_range(size).each do |idx|
|
1005
|
+
rtn.push @value[idx]
|
1006
|
+
end
|
1007
|
+
elsif ii.type_of? Array
|
1008
|
+
ii.each do |idx|
|
1009
|
+
rtn.push @value[idx]
|
1010
|
+
end
|
1011
|
+
else
|
1012
|
+
rtn.push @value[ii]
|
1013
|
+
end
|
1014
|
+
end
|
1015
|
+
return rtn
|
1016
|
+
end
|
1017
|
+
def []=(*list)
|
1018
|
+
data = list.pop
|
1019
|
+
list = PrimitiveWrapper::get_list(list,size)
|
1020
|
+
return nil if list.empty?
|
1021
|
+
if list.count==1
|
1022
|
+
if list.first.respond_to? :each
|
1023
|
+
list = list.first
|
1024
|
+
if list.type_of? Range
|
1025
|
+
list = list.to_xr.re_range(size)
|
1026
|
+
end
|
1027
|
+
end
|
1028
|
+
end
|
1029
|
+
if list.count==1
|
1030
|
+
if list.first == :all
|
1031
|
+
PrimitiveWrapper.copy(@value, data, :all)
|
1032
|
+
end
|
1033
|
+
idxs = list.first
|
1034
|
+
if (idxs.respond_to? :each)
|
1035
|
+
if idxs.type_of? Range
|
1036
|
+
idxs = idxs.to_xr.re_range(size)
|
1037
|
+
end
|
1038
|
+
idxs.each do |idx|
|
1039
|
+
@value[idx] = data
|
1040
|
+
end
|
1041
|
+
else
|
1042
|
+
@value[idxs] = data
|
1043
|
+
end
|
1044
|
+
else
|
1045
|
+
if data.type_of? Array
|
1046
|
+
data = PrimitiveWrapper::get_list(data,size)
|
1047
|
+
end
|
1048
|
+
PrimitiveWrapper.copy(@value, data, list)
|
1049
|
+
end
|
1050
|
+
end
|
1051
|
+
def delete_at(*index_list)
|
1052
|
+
return nil if index_list.empty?
|
1053
|
+
if (index_list.count==1)
|
1054
|
+
if index_list.first==:all
|
1055
|
+
self.empty!
|
1056
|
+
end
|
1057
|
+
else
|
1058
|
+
list = PrimitiveWrapper::get_list(index_list,size)
|
1059
|
+
rtn = []
|
1060
|
+
list.sort.reverse.each do |idx|
|
1061
|
+
rtn.push = @value.delete_at(idx)
|
1062
|
+
end
|
1063
|
+
return rtn
|
1064
|
+
end
|
1065
|
+
end
|
1066
|
+
def include?(*list) # replace with list of stuff
|
1067
|
+
if list.count==1
|
1068
|
+
if list.first.respond_to? :each
|
1069
|
+
list = list.first
|
1070
|
+
end
|
1071
|
+
end
|
1072
|
+
list.each do |item|
|
1073
|
+
return false unless @value.include? item
|
1074
|
+
end
|
1075
|
+
true
|
1076
|
+
end
|
1077
|
+
def include_any?(*list) # replace with list of stuff
|
1078
|
+
if list.count==1
|
1079
|
+
if list.first.respond_to? :each
|
1080
|
+
list = list.first
|
1081
|
+
end
|
1082
|
+
end
|
1083
|
+
list.each do |item|
|
1084
|
+
return true if @value.include? item
|
1085
|
+
end
|
1086
|
+
false
|
1087
|
+
end
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
|
1091
|
+
|
data/primitive_wrapper.gemspec
CHANGED
@@ -29,7 +29,11 @@ The `Property` object auto-methodizes the key names of the Hash.}
|
|
29
29
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
30
30
|
spec.require_paths = ["lib"]
|
31
31
|
|
32
|
-
spec.
|
32
|
+
spec.required_ruby_version = '>= 2.2.0'
|
33
|
+
|
34
|
+
spec.add_runtime_dependency 'blockify', '~> 0.2', '>= 0.2.0'
|
35
|
+
spec.add_runtime_dependency 'yieldhelper', '~> 0.1', '>= 0.1.0'
|
36
|
+
spec.add_runtime_dependency 'pred', '~> 0.1', '>= 0.1.2'
|
33
37
|
|
34
38
|
spec.add_development_dependency "bundler", "~> 1.11"
|
35
39
|
spec.add_development_dependency "rake", "~> 10.0"
|
metadata
CHANGED
@@ -1,19 +1,42 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: primitive_wrapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryan Colvin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: blockify
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.2'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.2.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.2'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.2.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: yieldhelper
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0.1'
|
17
40
|
- - ">="
|
18
41
|
- !ruby/object:Gem::Version
|
19
42
|
version: 0.1.0
|
@@ -21,9 +44,32 @@ dependencies:
|
|
21
44
|
prerelease: false
|
22
45
|
version_requirements: !ruby/object:Gem::Requirement
|
23
46
|
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0.1'
|
24
50
|
- - ">="
|
25
51
|
- !ruby/object:Gem::Version
|
26
52
|
version: 0.1.0
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: pred
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0.1'
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 0.1.2
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0.1'
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 0.1.2
|
27
73
|
- !ruby/object:Gem::Dependency
|
28
74
|
name: bundler
|
29
75
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,7 +175,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
129
175
|
requirements:
|
130
176
|
- - ">="
|
131
177
|
- !ruby/object:Gem::Version
|
132
|
-
version:
|
178
|
+
version: 2.2.0
|
133
179
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
180
|
requirements:
|
135
181
|
- - ">="
|