primitive_wrapper 0.1.0 → 1.0.0
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.
- 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
|
- - ">="
|