<commit_before>package com.miguelgaeta.bootstrap.mg_text;

import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.CharacterStyle;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import rx.Observable;

/**
 * Created by <NAME> on 9/11/15.
 */
@AllArgsConstructor(staticName = "create")
public class MGTextSpansBuilder {

    private @NonNull String sourceString;

    public void addReplacement(String targetStart, String targetEnd, Replacement replacement, boolean targetEndRequired) {

        // TODO
    }

    public void addReplacement(String targetStart, String targetEnd, Replacement replacement) {

        addReplacement(targetStart, targetEnd, replacement, true);
    }

    /**
     * Looks for any instances of the start target and matches them. Since
     * no end target is specified, no delimiter is needed.
     */
    public void addReplacement(String targetStart, Replacement replacement) {

        // TODO
    }

    /**
     * Given replacement strategies, build an associated
     * spannable string.
     */
    public SpannableString build() {

        return buildSpannableString(sourceString, buildSpans());
    }

    private SpannableString buildSpannableString(@NonNull final String sourceString, @NonNull final List<Span> spans) {

        final SpannableString spannableString = new SpannableString(sourceString);

        for (Span span: spans) {

            for (CharacterStyle characterStyle : span.spanStyles) {

                spannableString.setSpan(characterStyle, span.getStart(), span.getEnd(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }

        return spannableString;
    }

    private List<Span> buildSpans() {

        // TODO

        return new ArrayList<>();
    }

    /**
     * Build spannable string as an observable.
     */
    public Observable<SpannableString> buildObservable() {

        return Observable.create(subscriber -> {

            subscriber.onNext(build());
            subscriber.onCompleted();
        });
    }

    @AllArgsConstructor(staticName = "create") @Getter
    public static class Match {

        private final int start;

        private final int end;

        private final String content;
    }

    public static class Span {

        @Getter(value = AccessLevel.PRIVATE)
        private final String spanString;

        @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
        private final List<CharacterStyle> spanStyles;

        @Getter @Setter(value = AccessLevel.PRIVATE)
        private int start;

        @Getter @Setter(value = AccessLevel.PRIVATE)
        private int end;

        private Span(String spanString, List<CharacterStyle> spanStyles) {

            this.spanString = spanString;
            this.spanStyles = spanStyles;
        }

        public static Span create(String spanString, CharacterStyle... spanStyles) {

            final List<CharacterStyle> styles = new ArrayList<>();

            Collections.addAll(styles, spanStyles);

            return Span.create(spanString, styles);
        }

        public static Span create(String spanString, List<CharacterStyle> spanStyles) {

            return new Span(spanString, spanStyles);
        }
    }

    public interface Replacement {

        Span call(Match match);
    }
}<commit_msg>Solidified naming conventions.  Added the concept of match strategies which are now populated as a list to be used by the spannable build process.<commit_after>package com.miguelgaeta.bootstrap.mg_text;

import android.support.annotation.Nullable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.CharacterStyle;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import rx.Observable;

/**
 * Created by <NAME> on 9/11/15.
 */
@AllArgsConstructor(staticName = "create")
public class MGTextSpansBuilder {

    @NonNull
    private String sourceString;

    @NonNull @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
    private final List<MatchStrategy> matchStrategies = new ArrayList<>();

    public void addMatchStrategy(@NonNull String matchStart, @NonNull String matchEnd, @NonNull OnMatch onMatch) {

        addMatchStrategy(matchStart, matchEnd, onMatch, true);
    }

    public void addMatchStrategy(@NonNull String matchStart, @NonNull String matchEnd, @NonNull OnMatch onMatch, boolean matchEndRequired) {

        matchStrategies.add(MatchStrategy.create(matchStart, matchEnd, onMatch, matchEndRequired));
    }

    /**
     * Looks for any instances of the start target and matches them. Since
     * no end target is specified, no delimiter is needed.
     */
    public void addMatchStrategy(@NonNull String matchStart, @NonNull OnMatch onMatch) {

        matchStrategies.add(MatchStrategy.create(matchStart, null, onMatch, false));
    }

    /**
     * Given replacement strategies, build an associated
     * spannable string.
     */
    public SpannableString build() {

        return buildSpannableString(sourceString, buildSpans());
    }

    private SpannableString buildSpannableString(@NonNull final String sourceString, @NonNull final List<Span> spans) {

        final SpannableString spannableString = new SpannableString(sourceString);

        for (Span span: spans) {

            for (CharacterStyle characterStyle : span.spanStyles) {

                spannableString.setSpan(characterStyle, span.getStart(), span.getEnd(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }

        return spannableString;
    }

    private List<Span> buildSpans() {

        // TODO

        return new ArrayList<>();
    }

    /**
     * Build spannable string as an observable.
     */
    public Observable<SpannableString> buildObservable() {

        return Observable.create(subscriber -> {

            subscriber.onNext(build());
            subscriber.onCompleted();
        });
    }

    @AllArgsConstructor(staticName = "create") @Getter
    public static class Match {

        private final int start;

        private final int end;

        private final String content;
    }

    @AllArgsConstructor(staticName = "create")
    private static class MatchStrategy {

        @NonNull
        private final String matchStart;

        @Nullable
        private final String matchEnd;

        @NonNull
        private final OnMatch onMatch;

        private final boolean matchEndRequired;
    }

    public interface OnMatch {

        Span call(Match match);
    }

    public static class Span {

        @Getter(value = AccessLevel.PRIVATE)
        private final String spanString;

        @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
        private final List<CharacterStyle> spanStyles;

        @Getter @Setter(value = AccessLevel.PRIVATE)
        private int start;

        @Getter @Setter(value = AccessLevel.PRIVATE)
        private int end;

        private Span(String spanString, List<CharacterStyle> spanStyles) {

            this.spanString = spanString;
            this.spanStyles = spanStyles;
        }

        public static Span create(String spanString, CharacterStyle... spanStyles) {

            final List<CharacterStyle> styles = new ArrayList<>();

            Collections.addAll(styles, spanStyles);

            return Span.create(spanString, styles);
        }

        public static Span create(String spanString, List<CharacterStyle> spanStyles) {

            return new Span(spanString, spanStyles);
        }
    }
}
{'fraction_non_alphanumeric': 0.08323743766781741, 'fraction_numerical': 0.0012786088735455823, 'mean_word_length': 2.866534849233811, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6207089', 'n_tokens_mistral': 2100, 'n_tokens_neox': 2046, 'n_words': 558}