Skip to content

Commit

Permalink
Merge pull request #8 from warrenrhodes/add_custum_function
Browse files Browse the repository at this point in the history
add custom function
  • Loading branch information
warrenrhodes authored Jun 11, 2024
2 parents 0951b2b + 575f2a5 commit c0e2fb0
Show file tree
Hide file tree
Showing 9 changed files with 265 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 1.1.0

- Adds custom print function `fprint`.
- Adds `prod` function on integer list.
- Adds `swapcase`, `format` and `isDigit` on string extenxion.

## 1.0.1

- Add `DateTimeExtensions` extension
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Add the following dependency to your `pubspec.yaml` file:

```yaml
dependencies:
dart_advanced_utils: ^1.0.0
dart_advanced_utils: ^1.1.0
```
Run `pub get` to install the package.
Expand All @@ -35,6 +35,7 @@ import 'package:dart_advanced_utils/dart_advanced_utils.dart';
- **median**: Calculates the median of all elements in the list.
- **min**: Find the minimum value in the list.
- **max**: Find the maximum value in the list.
- **prod**: Returns the product of all elements in the list.

### String Extensions

Expand All @@ -55,6 +56,9 @@ import 'package:dart_advanced_utils/dart_advanced_utils.dart';
- **strip**: Returns a new string with leading and trailing characters removed.
- **title**: Returns a new string with the first letter of each word capitalized and all other letters lowercased.
- **charToUpper**: Returns a new string with the character at the specified [index] capitalized.
- **format**: Formats the string by replacing placeholders with provided arguments.
- **isDigit**: Returns `true` if the string contains only digits, and `false` otherwise
- **swapcase**: Returns a new string with the case of each character swapped.

### Date Extensions

Expand All @@ -73,6 +77,10 @@ import 'package:dart_advanced_utils/dart_advanced_utils.dart';
- **endOfMonth**Returns the last day of the month for a given date.
- **hasALeapYear** Determines if the year of a given date is a leap year.

### Custom Function

- **fprint** A formatted print function.

### Examples

```dart
Expand Down
13 changes: 13 additions & 0 deletions example/dart_advanced_utils_example.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:dart_advanced_utils/dart_advanced_utils.dart';
import 'package:dart_advanced_utils/src/custom_func.dart';

void main() {
List<int> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
Expand All @@ -20,4 +21,16 @@ void main() {

String? blankString = " ";
print(blankString.isBlank); // Output: true

print(numbers.prod); // Output: 3628800

String str = 'Hello {0}, my name is {1}';
String str2 = 'Hello {}, my name is {}';
print(str.format(
posArgs: ['Dart', 'John'])); // Output: Hello Dart, my name is John.
print(str2.format(
posArgs: ['Jhon', 'Smith'])); //Output: Hello Jhon, my name is Smith.

final iterable = ['value1', 'value2'];
fprint(iterable, unpack: true); // Output: value1 value2
}
34 changes: 34 additions & 0 deletions lib/src/custom_func.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/// A formatted print function.
///
/// The function takes a list of objects to print, a separator to use between
/// the objects, an end character to append at the end of the output, and an
/// optional file to write the output to.
///
/// Args:
/// args (Object?): The list of objects to print.
/// sep (String?): The separator to use between objects. Defaults to a space.
/// end (String): The end character to append at the end. Defaults to a newline.
/// unpack (bool): Whether to unpack the map or iterable objects. Defaults to false.
///
/// Example:
/// fprint(['Hello', 'world', 123], sep: ', ', end: '!\n');
/// fprint(['Dart', 'is', 'fun']);
void fprint(Object? args,
{String sep = ' ', String end = '\n', bool unpack = false}) {
String output;
if (args is Map) {
if (unpack) {
output = args.keys.join(sep);
} else {
output = args.toString();
}
} else if (args is Iterable) {
output = unpack ? args.join(sep) : args.toString();
} else {
output = args.toString();
}

output += end;

print(output);
}
15 changes: 15 additions & 0 deletions lib/src/list_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,19 @@ extension IntList<T extends num> on Iterable<T> {
T get min => length == 0
? throw StateError('No element')
: reduce((curr, next) => curr < next ? curr : next);

/// Returns the product of all elements in the list.
///
/// If the list is empty, a [StateError] is thrown with the message 'No element'.
///
/// Returns the product of all elements in the list.
///
/// Example:
/// ```dart
/// List<int> numbers = [1, 2, 3];
/// print(numbers.prod); // Output: 6
///
num get prod => length == 0
? throw StateError('No element')
: fold(1, (current, next) => current * next);
}
124 changes: 124 additions & 0 deletions lib/src/string_extensions.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
extension NullStringExtensions on String? {
/// Returns `true` if the string is `null` or empty, `false` otherwise.
///
/// This getter checks if the string is `null` or if it is empty. It returns `true` if the string is `null` or if it has no characters.
///
/// Example:
/// ```dart
/// final String? myString = null;
/// final bool isNullOrEmpty = myString.isNullOrEmpty;
/// print(isNullOrEmpty); // Prints true
///
/// final String emptyString = '';
/// final bool isNullOrEmpty2 = emptyString.isNullOrEmpty;
/// print(isNullOrEmpty2); // Prints true
///
/// final String nonEmptyString = 'Hello, world!';
/// final bool isNullOrEmpty3 = nonEmptyString.isNullOrEmpty;
/// print(isNullOrEmpty3); // Prints false
/// ```
///
/// Returns:
/// - `true` if the string is `null` or empty.
/// - `false` otherwise.
bool get isNullOrEmpty => this == null || this!.isEmpty;
}

/// Extensions for formatting strings.
///
/// This extension provides methods for formatting strings.
Expand Down Expand Up @@ -366,4 +392,102 @@ extension StringFormat on String {
int get wordCount {
return trim().split(RegExp(r'\s+')).length;
}

/// Returns a new string with the case of each character swapped.
///
/// If the string is empty, it returns the original string.
///
/// Example:
/// ```dart
/// String str = "Hello world";
/// print(str.swapcase); // Output: hELLO wORLD
/// ```
String get swapcase {
if (isEmpty) return this;
return split('').map((char) {
if (char == char.toUpperCase()) return char.toLowerCase();
return char.toUpperCase();
}).join('');
}

/// Returns `true` if the string contains only digits, and `false` otherwise.
///
/// This getter uses a regular expression to check if the string consists of one or more digits.
///
/// Example:
/// ```dart
/// String str1 = "123";
/// print(str1.isDigit); // Output: true
///
/// String str2 = "abc";
/// print(str2.isDigit); // Output: false
/// ```
bool get isDigit => RegExp(r'^[0-9]+$').hasMatch(this);

/// Formats the string by replacing placeholders with provided arguments.
///
/// The function takes an optional list of positional arguments [posArgs] and
/// an optional map of named arguments [namedArgs]. The placeholders in the
/// string can be specified using curly braces `{}` for positional arguments
/// and `${name}` for named arguments. The function replaces these placeholders
/// with the corresponding values from the arguments.
///
/// If [sep] is provided, it is used to join the words in the formatted string.
///
/// Returns the formatted string.
///
/// Example:
/// ```dart
/// String str = 'Hello {0}, my name is {1}';
/// String str2 = 'Hello {}, my name is {}';
/// print(str.format(posArgs: ['Dart', 'John'])); Output: Hello Dart, my name is John.
/// print(str2.format(posArgs: ['Jhon', 'Smith'])); Output: Hello Jhon, my name is Smith.
/// ```
String format(
{List<dynamic>? posArgs, Map<String, dynamic>? namedArgs, String? sep}) {
String result = this;

if (posArgs != null) {
for (int i = 0; i < posArgs.length; i++) {
result = result
.replaceAll('{$i}', posArgs[i].toString())
.replaceFirst('{}', posArgs[i].toString());
}
}

if (namedArgs != null) {
namedArgs.forEach((key, value) {
result = result.replaceAll('{$key}', value.toString());
});
}

return result.split(' ').join(sep ?? ' ');
}

/// Returns `true` if the string is a valid URL, `false` otherwise.
///
/// This getter checks if the string matches the regular expression pattern for a valid URL.
/// It returns `true` if the string is a valid URL, and `false` otherwise.
///
/// Example:
/// ```dart
/// final String url1 = 'https://www.example.com';
/// final bool isValidUrl1 = url1.isValidUrl;
/// print(isValidUrl1); // Prints true
///
/// final String url2 = 'ftp://example.com';
/// final bool isValidUrl2 = url2.isValidUrl;
/// print(isValidUrl2); // Prints true
///
/// final String url3 = 'example.com';
/// final bool isValidUrl3 = url3.isValidUrl;
/// print(isValidUrl3); // Prints false
/// ```
///
/// Returns:
/// - `true` if the string is a valid URL.
/// - `false` otherwise.
bool get isUrl => RegExp(
r"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$")
.hasMatch(this);
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: dart_advanced_utils
description: A Dart advanced utils package enhances the default dart object by adding powerful and flexible methods.
version: 1.0.1
version: 1.1.0
repository: https://github.com/warrenrhodes/dart_utils
issue_tracker: https://github.com/warrenrhodes/dart_utils/issues

Expand Down
58 changes: 58 additions & 0 deletions test/custom_func_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import 'package:dart_advanced_utils/src/custom_func.dart';
import 'package:test/test.dart';

void main() {
group('fprint', () {
test('should print a map with unpacked keys', () {
final map = {'key1': 'value1', 'key2': 'value2'};
final expectedOutput = 'key1 key2';

expect(() => fprint(map, unpack: true), prints('$expectedOutput\n\n'));
});

test('should print a map with string representation', () {
final map = {'key1': 'value1', 'key2': 'value2'};
final expectedOutput = '{key1: value1, key2: value2}';

expect(() => fprint(map), prints('$expectedOutput\n\n'));
});

test('should print an iterable with unpacked elements', () {
final iterable = ['value1', 'value2'];
final expectedOutput = 'value1 value2';

output() => fprint(iterable, unpack: true);

expect(output, prints('$expectedOutput\n\n'));
});

test(
'should print an iterable with unpacked elements and string representation',
() {
final iterable = ['value1', 'value2'];
final expectedOutput = 'value1-value2';

output() => fprint(iterable, unpack: true, sep: '-');

expect(output, prints('$expectedOutput\n\n'));
});

test('should print an iterable with string representation', () {
final iterable = ['value1', 'value2'];
final expectedOutput = '[value1, value2]';

output() => fprint(iterable);

expect(output, prints('$expectedOutput\n\n'));
});

test('should print a single value', () {
final value = 'value';
final expectedOutput = 'value';

output() => fprint(value);

expect(output, prints('$expectedOutput\n\n'));
});
});
}
6 changes: 5 additions & 1 deletion test/list_extensions_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ void main() {
List<List<int>> emptyList = [[]];
List<List<int>> repeatedList = emptyList * 3;
List repeatedList2 = [54] * 3;

expect(repeatedList, [[], [], []]);
expect(repeatedList2, [54, 54, 54]);
});
Expand Down Expand Up @@ -79,6 +78,11 @@ void main() {
expect(numbers.min, equals(1));
});

test('prod of non-empty iterable', () {
var numbers = [1, 2, 3, 4, 5];
expect(numbers.prod, equals(120));
});

test('empty iterable throws StateError', () {
List<int> numbers = [];
expect(() => numbers.sum, throwsA(isA<StateError>()));
Expand Down

0 comments on commit c0e2fb0

Please sign in to comment.