platform/packages/support/lib/src/stringable.dart

333 lines
9.3 KiB
Dart

import 'package:platform_macroable/platform_macroable.dart';
import 'package:platform_conditionable/platform_conditionable.dart';
import 'traits/dumpable.dart';
import 'traits/tappable.dart';
import 'facades/date.dart';
import 'carbon.dart';
import 'str.dart';
/// A class that provides string manipulation capabilities.
class Stringable with Macroable, Conditionable, Dumpable, Tappable {
/// The underlying string value.
String _value;
/// Create a new stringable instance.
Stringable(this._value);
/// Get the string length.
int getLength() => Str.length(_value);
/// Convert the given string to camel case.
Stringable camel() {
_value = Str.camel(_value);
return this;
}
/// Convert the given string to studly caps case.
Stringable studly() {
_value = Str.studly(_value);
return this;
}
/// Convert a string to snake case.
Stringable snake([String separator = '_']) {
if (_value.isEmpty) return this;
final result = StringBuffer();
result.write(_value[0].toLowerCase());
for (var i = 1; i < _value.length; i++) {
if (_value[i].toUpperCase() == _value[i] &&
_value[i].toLowerCase() != _value[i]) {
result.write(separator);
result.write(_value[i].toLowerCase());
} else {
result.write(_value[i]);
}
}
_value = result.toString().replaceAll('_', separator);
return this;
}
/// Convert a string to kebab case.
Stringable kebab() {
_value = snake('-').toString();
return this;
}
/// Convert the given string to title case.
Stringable title() {
_value = Str.title(_value);
return this;
}
/// Convert the given string to lower case.
Stringable lower() {
_value = Str.lower(_value);
return this;
}
/// Convert the given string to upper case.
Stringable upper() {
_value = Str.upper(_value);
return this;
}
/// Generate a URL friendly "slug" from a given string.
Stringable slug([String separator = '-']) {
_value = Str.slug(_value, separator: separator);
return this;
}
/// Convert a string to its ASCII representation.
Stringable ascii() {
_value = Str.ascii(_value);
return this;
}
/// Determine if a given string starts with a given substring.
bool startsWith(dynamic needles) => Str.startsWith(_value, needles);
/// Determine if a given string ends with a given substring.
bool endsWith(dynamic needles) => Str.endsWith(_value, needles);
/// Cap a string with a single instance of a given value.
Stringable finish(String cap) {
_value = Str.finish(_value, cap);
return this;
}
/// Begin a string with a single instance of a given value.
Stringable start(String prefix) {
_value = Str.start(_value, prefix);
return this;
}
/// Determine if a given string contains a given substring.
bool contains(dynamic needles) => Str.contains(_value, needles);
/// Limit the number of characters in a string.
Stringable limit(int limit, [String end = '...']) {
_value = Str.limit(_value, limit, end);
return this;
}
/// Convert the given string to base64.
Stringable toBase64() {
_value = Str.toBase64(_value);
return this;
}
/// Convert the given base64 string back to a normal string.
Stringable fromBase64() {
_value = Str.fromBase64(_value);
return this;
}
/// Parse a Class[@]method style callback string.
List<String>? parseCallback([String separator = '@']) =>
Str.parseCallback(_value, separator);
/// Mask a portion of a string with a repeated character.
Stringable mask(int start, [int? length, String mask = '*']) {
if (start < 0 || start >= _value.length) return this;
final maskLength = length ?? (_value.length - start);
final end = start + maskLength;
if (end > _value.length) return this;
final original = _value;
_value = original.substring(0, start) +
(length != null ? mask * length : mask * (original.length - start)) +
(length != null ? original.substring(end) : '');
return this;
}
/// Pad both sides of a string with another.
Stringable padBoth(int length, [String pad = ' ']) {
final remaining = length - _value.length;
if (remaining <= 0) return this;
final leftPad = pad * (remaining ~/ 2);
final rightPad = remaining % 2 == 0
? pad * (remaining ~/ 2)
: pad * ((remaining - leftPad.length));
_value = leftPad + _value + rightPad;
return this;
}
/// Pad the left side of a string with another.
Stringable padLeft(int length, [String pad = ' ']) {
final remaining = length - _value.length;
if (remaining <= 0) return this;
_value = pad * remaining + _value;
return this;
}
/// Pad the right side of a string with another.
Stringable padRight(int length, [String pad = ' ']) {
final remaining = length - _value.length;
if (remaining <= 0) return this;
_value = _value + pad * remaining;
return this;
}
/// Split a string by a regular expression.
List<String> split(Pattern pattern) => _value.split(pattern);
/// Get a substring of the given string.
Stringable substr(int start, [int? length]) {
if (start < 0) start = _value.length + start;
if (start < 0) start = 0;
if (start >= _value.length) return this;
final end = length != null ? start + length : _value.length;
_value = _value.substring(start, end > _value.length ? _value.length : end);
return this;
}
/// Replace all occurrences of the search string with the replacement string.
Stringable replace(Pattern from, String replace) {
_value = _value.replaceAll(from, replace);
return this;
}
/// Replace the first occurrence of the search string with the replacement string.
Stringable replaceFirst(Pattern from, String replace) {
_value = _value.replaceFirst(from, replace);
return this;
}
/// Replace the last occurrence of the search string with the replacement string.
Stringable replaceLast(Pattern from, String replace) {
final matches = from.allMatches(_value).toList();
if (matches.isNotEmpty) {
final lastMatch = matches.last;
_value = _value.substring(0, lastMatch.start) +
replace +
_value.substring(lastMatch.end);
}
return this;
}
/// Convert the string to a boolean value.
bool toBoolean() {
final lower = _value.toLowerCase();
return lower == 'true' || lower == '1' || lower == 'yes' || lower == 'on';
}
/// Trim the string of whitespace.
Stringable trim() {
_value = _value.trim();
return this;
}
/// Trim the string of the given characters.
Stringable trimChars(String chars) {
for (var i = 0; i < chars.length; i++) {
final char = chars[i];
while (_value.startsWith(char)) {
_value = _value.substring(1);
}
while (_value.endsWith(char)) {
_value = _value.substring(0, _value.length - 1);
}
}
return this;
}
/// Get the string between the given start and end delimiters.
Stringable between(String start, String end) {
final startPos = _value.indexOf(start);
if (startPos != -1) {
final endPos = _value.indexOf(end, startPos + start.length);
if (endPos != -1) {
_value = _value.substring(startPos + start.length, endPos);
}
}
return this;
}
/// Get the portion of a string before a given value.
Stringable before(String search) {
final pos = _value.indexOf(search);
if (pos != -1) {
_value = _value.substring(0, pos);
}
return this;
}
/// Get the portion of a string after a given value.
Stringable after(String search) {
final pos = _value.indexOf(search);
if (pos != -1) {
_value = _value.substring(pos + search.length);
}
return this;
}
/// Get the portion of a string before the last occurrence of a given value.
Stringable beforeLast(String search) {
final pos = _value.lastIndexOf(search);
if (pos != -1) {
_value = _value.substring(0, pos);
}
return this;
}
/// Get the portion of a string after the last occurrence of a given value.
Stringable afterLast(String search) {
final pos = _value.lastIndexOf(search);
if (pos != -1) {
_value = _value.substring(pos + search.length);
}
return this;
}
/// Determine if a given string matches a given pattern.
bool matches(Pattern pattern) => pattern.allMatches(_value).isNotEmpty;
/// Parse the string into a Carbon instance.
Carbon toDate() => Date.parse(_value);
/// Get the string value.
@override
String toString() => _value;
/// Compare this string with another string.
bool equals(String other) => _value == other;
/// Get the hash code for this string.
@override
int get hashCode => _value.hashCode;
/// Compare this string with another object.
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is Stringable && other._value == _value;
}
/// Create a new stringable instance from a string.
static Stringable from(String value) => Stringable(value);
/// Dump the string value.
@override
T dump<T extends Object>([List<Object?>? args]) {
print(_value);
if (args != null) {
for (final arg in args) {
print(arg);
}
}
return this as T;
}
/// Dump the string value and die.
@override
Never dd([List<Object?>? args]) {
dump(args);
throw Exception('Dump and die');
}
}