# Using

Once you create a `Scope` and inject `values` you can access those values from any method called within the context of the Scope.

By 'context' we mean any method that sits below the Scope's `run` method on the call stack:

```dart
import 'package:scope/scope.dart';
void httpRequestHandler(HttpRequest request)
{
    /// create a scope
    Scope()
        ..value<HttpRequest>(requestKey, request)
        ..value<int>(ageKey, 18)
        ..run(() => a());   /// call a() from within the scope
}

void a() => b();
void b() => c();

void c() {
    // c is within the scope, so we can call 'use' to access values
    // in the scope.
    print('Your are ${use(ageKey)} years old');
    
    print('Your ip is: ${use(requestKey).clientIp}');
}
```

You can see from the above example that the method `c` was call from `b` which was called from `a` which was called from the Scope's `run` method thus `c` is in the Scope's context.

Scope.run -> a ->b ->c

So a, b, and c are all within the Scope's context and have access to the Scope's values.

The `use` method provide access to injected values that exist in our scope **or any ancestors scope**.

To obtain an injected value we can call either of the two forms of `use`. The two forms are equivalent and exist simply for convenience.

```dart
     var age = use(ageKey);
     var name = Scope.use(ageKey);
```

The first version is concise whilst the second version provides better documentation.

ScopeKeys are typed and as such the result of `use` is also typed.

```dart
var ageKey = ScopeKey<int>();
var age = use(ageKey);
age is int;
```

### Missing ScopeKey

If you call `use(somekey)` and `somekey` hasn't been added to your Scope then a `MissingDependencyException` will be thrown.

You can avoid this problem using one of the following techniques:

### Default values

The most elegant method is to use a default.

You can set a default when:

* you create the scopeKey
* you call use

#### ScopeKey default

When creating a ScopeKey you can set a default value.

Any time `use` is called for that ScopeKey and the ScopeKey is not in Scope then the default will be returned.

The default is fixed for the life of the ScopeKey.

```dart
ScopeKey<int> countKey = ScopeKey.withDefault<int>(0);

count = use(countKey);

```

#### Use default

This is perhaps the most useful method as it allows you to provide a default value from where you call `use`.

```dart
final count = use(countKey, withDefault: () => nextCount++);
```

We use a lambda `() =>` for the default value to help with performance. The lambda provided to the `default` argument will only be called if the ScopeKey is missing. This allows the default to call a potentially long running method.

If the ScopeKey was created using `Scope.withDefault` and you call `use` with a default value then the default value provided to `use` will take precedence.

```dart
ScopeKey<int> countKey = ScopeKey.withDefault<int>(0);

count = use(countKey, withDefault: () => 1);
expect(count, equals(1));
```

#### hasScopeKey

Before calling `use` can test if the ScopeKey exists by calling `hasScopeKey()` or `Scope.hasScopeKey`

```dart
final int count;
if (hasScopeKey(countKey)) {
   count = use(countKey);
} else count = 1;
```

#### hasScopeValue

hasScopeValue works like `hasScopeKey` in that it checks if a key is in scope. The difference is that if the key isn't in scope but has a default value then `hasScopeValue` will return true.

```dart
final countKey = ScopeKey.withDefault<int>(10);
final int count;
if (hasScopeValue(countKey)) {
   count = use(countKey);
} else count = 20;

expect(count, equals(10));
```

#### isWithinScope

You can check if you are within a Scope by calling `isWithinScope()` or `Scope.isWithinScope().`

This method isn't very reliable as it may turn out that you are running in someone else's scope.

```dart
final int count;
if (isWithinScope()) {
   count = use(countKey);
} 
else count = 1;
```
