# Is there a 'clamp' method/sub for ranges/Num etc in Raku (i.e. Perl6)?

Another tact you might like to explore is using a Proxy, which allows you to define "hooks" when fetching or storing a value from a container

```
sub limited-num(Range $range) is rw {
my ($min, $max) = $range.minmax;
my Numeric $store = $min;
Proxy.new(
FETCH => method () { $store },
STORE => method ($new) {
$store = max($min, min($max, $new));
}
)
}
# Note the use of binding operator `:=`
my $ln := limited-num(1.0 .. 9.9);
say $ln; # OUTPUT: 1
$ln += 4.2;
say $ln; # OUTPUT: 5.2
$ln += 100;
say $ln; # OUTPUT: 9.9
$ln -= 50;
say $ln; # OUTPUT: 1
$ln = 0;
say $ln; # OUTPUT: 1
```

This particular `limited-num`

will initialise with it's min value, but you can also set it at declaration

```
my $ln1 := limited-num(1.0 .. 9.9) = 5.5;
say $ln1; # OUTPUT 5.5;
my $ln2 := limited-num(1.0 .. 9.9) = 1000;
say $ln2; # OUTPUT 9.9
```

I don't think so. So, perhaps:

```
multi clamp ($range, $value) {
given $range {
return .max when (($value cmp .max) === More);
return .min when (($value cmp .min) === Less);
}
return $value
}
my $range = (1.0 .. 9.9);
say $range.&clamp: 15.3; # 9.9
say $range.&clamp: -1.3; # 1
my $range = 'b'..'y';
say $range.&clamp: 'a'; # b
say $range.&clamp: 'z'; # y
```

The MOP allows direct exploration of the objects available in your P6 system. A particularly handy metamethod is `.^methods`

which works on most built in objects:

```
say Range.^methods; # (new excludes-min excludes-max infinite is-int ...
```

By default this includes just the methods defined in the `Range`

class, not the methods it inherits. (To get them all you could use `say Range.^methods: :all`

. That'll net you a much bigger list.)

When I just tried it I found it also included a lot of methods unhelpfully named `Method+{is-nodal}.new`

. So maybe use this instead:

```
say Range.^methods.grep: * !~~ / 'is-nodal' /;
```

This netted:

```
(new excludes-min excludes-max infinite is-int elems iterator
flat reverse first bounds int-bounds fmt ASSIGN-POS roll pick
Capture push append unshift prepend shift pop sum rand in-range
hyper lazy-if lazy item race of is-lazy WHICH Str ACCEPTS perl
Numeric min max BUILDALL)
```

That's what I used to lead me to my solution above; I sort of know the methods but use `.^methods`

to remind me.

Another way to explore what's available is doc, eg the official doc's `Range`

page. That netted me:

```
ACCEPTS min excludes-min max excludes-max bounds
infinite is-int int-bounds minmax elems list flat
pick roll sum reverse Capture rand
```

Comparing these two lists, sorted and bagged, out of curiosity:

```
say
<ACCEPTS ASSIGN-POS BUILDALL Capture Numeric Str WHICH append
bounds elems excludes-max excludes-min first flat fmt hyper
in-range infinite int-bounds is-int is-lazy item iterator
lazy lazy-if max min new of perl pick pop prepend push
race rand reverse roll shift sum unshift>.Bag
∩
<ACCEPTS Capture bounds elems excludes-max excludes-min flat
infinite int-bounds is-int list max min minmax pick
rand reverse roll sum>.Bag
```

displays:

```
Bag(ACCEPTS, Capture, bounds, elems, excludes-max, excludes-min,
flat, infinite, int-bounds, is-int, max, min, pick,
rand, reverse, roll, sum)
```

So for some reason, `list`

, `minmax`

, and `sum`

are documented as `Range`

methods but are not listed by my `.^methods`

call. Presumably they're called `Method+{is-nodal}.new`

. Hmm.

```
say Range.^lookup('minmax'); # Method+{is-nodal}.new
say Range.^lookup('minmax').name; # minmax
```

Yep. Hmm. So I could have written:

```
say Range.^methods>>.name.sort;
(ACCEPTS ASSIGN-POS AT-POS BUILDALL Bag BagHash Capture EXISTS-POS
Mix MixHash Numeric Set SetHash Str WHICH append bounds elems
excludes-max excludes-min first flat fmt hyper in-range infinite
int-bounds is-int is-lazy item iterator lazy lazy-if list max min
minmax new of perl pick pop prepend push race rand reverse roll
shift sum unshift)
```

Anyhow, hope that's helpful.