From 51ea3f1a55caab282934c5374ce756f99dd027d9 Mon Sep 17 00:00:00 2001 From: maRci002 Date: Sun, 19 Dec 2021 22:12:03 +0100 Subject: [PATCH] initial --- .gitignore | 56 +++++++++++++ .vscode/launch.json | 14 ++++ CHANGELOG.md | 3 + LICENSE | 29 +++++++ README.md | 49 ++++++++++++ analysis_options.yaml | 30 +++++++ example/reference_wrapper_example.dart | 24 ++++++ lib/reference_wrapper.dart | 3 + lib/src/reference_wrapper.dart | 96 ++++++++++++++++++++++ pubspec.yaml | 12 +++ test/reference_wrapper_test.dart | 106 +++++++++++++++++++++++++ 11 files changed, 422 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 analysis_options.yaml create mode 100644 example/reference_wrapper_example.dart create mode 100644 lib/reference_wrapper.dart create mode 100644 lib/src/reference_wrapper.dart create mode 100644 pubspec.yaml create mode 100644 test/reference_wrapper_test.dart diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8372b07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,56 @@ +# Created by https://www.toptal.com/developers/gitignore/api/dart,visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=dart,visualstudiocode + +### Dart ### +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +build/ +# If you're building an application, you may want to check-in your pubspec.lock +pubspec.lock + +# Directory created by dartdoc +# If you don't generate documentation locally you can remove this line. +doc/api/ + +# dotenv environment variables file +.env* + +# Avoid committing generated Javascript files: +*.dart.js +*.info.json # Produced by the --dump-info flag. +*.js # When generated by dart2js. Don't specify *.js if your + # project includes source files written in JavaScript. +*.js_ +*.js.deps +*.js.map + +.flutter-plugins +.flutter-plugins-dependencies + +### Dart Patch ### +# dotenv environment variables file +.env + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# Support for Project snippet scope +!.vscode/*.code-snippets + +# End of https://www.toptal.com/developers/gitignore/api/dart,visualstudiocode diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..4247661 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "reference_wrapper", + "program": "example/reference_wrapper_example.dart", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..90b709e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version of the package. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5f61129 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2021, Márton Matuz +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..86c4620 --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +`Reference Wrapper` is a Dart package which simulates `pass by reference` feature using Wrapper class which holds the value. + +# Usage +> Use this package if you are calling a function that needs to modify its arguments + +## There are two ways to read / write the value + +```dart +var x = Ref(null); +var read1 = x.ref; // first way to read +var read2 = x(); // second way to read + +x.ref = 10; // first way to write +x(10); // second way to write +``` + +## Example +```dart +void twice(Ref x, Ref y) { + x.ref *= 2; + y.ref *= 2; +} + +void test() { + var x = Ref(5); + var y = Ref(7); + + twice(x, y); + print(x.ref); // 10 + print(y.ref); // 14 +} +``` + +## Advanced Example +```dart +void twice(Ref x, Ref y) { + x(x() * 2); + y(y() * 2); +} + +void test() { + var x = Ref(5); + var y = Ref(7); + + twice(x, y); + print(x()); // 10 + print(y()); // 14 +} +``` \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/example/reference_wrapper_example.dart b/example/reference_wrapper_example.dart new file mode 100644 index 0000000..7de6f73 --- /dev/null +++ b/example/reference_wrapper_example.dart @@ -0,0 +1,24 @@ +import 'package:reference_wrapper/reference_wrapper.dart'; + +void twice(Ref x, Ref y) { + x.ref *= 2; + y.ref *= 2; +} + +void twiceAdvanced(Ref x, Ref y) { + x(x() * 2); + y(y() * 2); +} + +void main() { + var x = Ref(5); + var y = Ref(7); + + twice(x, y); + print(x.ref); // 10 + print(y.ref); // 14 + + twiceAdvanced(x, y); + print(x()); // 20 + print(y()); // 28 +} diff --git a/lib/reference_wrapper.dart b/lib/reference_wrapper.dart new file mode 100644 index 0000000..78f6ccd --- /dev/null +++ b/lib/reference_wrapper.dart @@ -0,0 +1,3 @@ +library reference_wrapper; + +export 'src/reference_wrapper.dart'; diff --git a/lib/src/reference_wrapper.dart b/lib/src/reference_wrapper.dart new file mode 100644 index 0000000..b9a6af8 --- /dev/null +++ b/lib/src/reference_wrapper.dart @@ -0,0 +1,96 @@ +/// Wraps an arbitary object, if caller method pass [Ref] to callee method, then +/// any changes made on [Ref.ref] will affect caller too. +/// +/// There are two ways to read / write the value: +/// +/// ```dart +/// var x = Ref(null); +/// x.ref; // first way to read +/// x(); // second way to read +/// +/// x.ref = 10; // first way to write +/// x(15); // second way to write +/// ``` +/// +/// **Example:** +/// ```dart +/// void twice(Ref x, Ref y) { +/// x.ref *= 2; +/// y.ref *= 2; +/// } +/// +/// void test() { +/// var x = Ref(5); +/// var y = Ref(7); +/// +/// twice(x, y); +/// print(x.ref); // 10 +/// print(y.ref); // 14 +/// } +/// ``` +/// +/// **Advanced Example:** +/// ```dart +/// void twiceAdvanced(Ref x, Ref y) { +/// x(x() * 2); +/// y(y() * 2); +/// } +/// +/// void test() { +/// var x = Ref(5); +/// var y = Ref(7); +/// +/// twiceAdvanced(x, y); +/// print(x()); // 10 +/// print(y()); // 14 +/// } +/// ``` +abstract class Ref { + Ref._(); + + factory Ref(T ref) = _Ref; + + T get ref; + + set ref(T ref); + + T call([T ref]); + + Type get genericRuntimeType; + + static Type genericStaticType(Ref ref) => S; + + @override + String toString() => 'Ref(ref: $ref)'; +} + +class _Undefined {} + +class _Ref extends Ref { + @override + T ref; + + _Ref(this.ref) : super._(); + + @override + T call([Object? ref = _Undefined]) { + return identical(ref, _Undefined) ? this.ref : this.ref = ref as T; + } + + @override + Type get genericRuntimeType => T; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is _Ref && + other.genericRuntimeType == genericRuntimeType && + other.ref == ref; + } + + @override + int get hashCode => ref.hashCode; +} diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..491e5a3 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,12 @@ +name: reference_wrapper +description: A Dart package which simulates pass by reference feature. +version: 1.0.0 +repository: https://github.com/maRci002/reference_wrapper +homepage: https://github.com/maRci002/reference_wrapper + +environment: + sdk: '>=2.12.0 <3.0.0' + +dev_dependencies: + lints: ^1.0.0 + test: ^1.16.0 diff --git a/test/reference_wrapper_test.dart b/test/reference_wrapper_test.dart new file mode 100644 index 0000000..49ba8fa --- /dev/null +++ b/test/reference_wrapper_test.dart @@ -0,0 +1,106 @@ +import 'package:reference_wrapper/reference_wrapper.dart'; +import 'package:test/test.dart'; + +void twice(Ref x, Ref y) { + x.ref *= 2; + y.ref *= 2; +} + +void twiceAdvanced(Ref x, Ref y) { + x(x() * 2); + y(y() * 2); +} + +void changeTo(Ref ref, T to) { + ref(to); +} + +void main() { + group('Ref Tests', () { + group('Non-nullable Ref:', () { + late Ref x; + late Ref y; + + setUp(() { + x = Ref(5); + y = Ref(7); + }); + + test('calle method change should affect x and y', () { + twice(x, y); + expect(x.ref, 10); + expect(y.ref, 14); + }); + + test( + 'calle method change should affect x and y ' + 'using Callable class syntax', () { + twiceAdvanced(x, y); + expect(x(), 10); + expect(y(), 14); + }); + }); + + group('Nullable Ref:', () { + late Ref x; + + setUp(() { + x = Ref(5); + }); + + test('changeTo method\'s changes should affect x', () { + changeTo(x, null); + expect(x.ref, null); + expect(x(), null); + }); + }); + + group('Type validations:', () { + test( + 'throws TypeError when nullable generictype is casted ' + 'to non-nullable', () { + expect( + () => Ref(11) as Ref, + throwsA( + isA(), + ), + ); + }); + + test( + 'throws TypeError when x is fake casted to nullable and ' + 'changeTo tries to set it\'s value to null', () { + expect( + // ignore: unnecessary_cast + () => changeTo(Ref(11) as Ref, null), + throwsA( + isA(), + ), + ); + }); + + test( + '== operator should return true if two Ref\'s value are same ' + 'and genericType are same', () { + expect(Ref(11) == Ref(11), true); + }); + + test( + '== operator should return false if two Ref\'s value are same ' + 'and genericType are not same', () { + expect(Ref(11) == Ref(11), false); + }); + + test( + '== operator should return false if two Ref\'s value are not same ' + 'and genericType are same', () { + expect(Ref(11) == Ref(10), false); + }); + + test('genericRuntimeType and genericStaticType should be different', () { + Ref x = Ref(10); + expect(Ref.genericStaticType(x) == x.genericRuntimeType, false); + }); + }); + }); +}