"helps" sometimes) → using someone's (undocumented) API without looking at the implementation? → using an undocumented API you wrote in the past, without looking at the implementation? 9 — @basthomas
array_2.clone end def combine_outputs concat_arrays end private def occurrences @array_1.count(@array_2.first) end def occurred_at_index(array) array.index(@array_2.first) end def occurrence_chunks chunks = [] array = @array_1.clone occurrences.times do occurrence_index = occurred_at_index(array) chunks << array[occurrence_index..array.count] array.delete_at(occurrence_index) end chunks end # more of this end 12 — @basthomas
removing the duplicates in the parts that are not overlap completely (in the meaning that we care only if the last x values of 1st array overlaps with the same x values of the 2nd, but we don't care if some duplicates are randomly exist in the body of array) 16 — @basthomas
strings collected till # this moment # @param array_2 [Array] an array that contain new elements that should be # added in array_1 def initialize(array_1, array_2) @array_1 = array_1.clone @array_2 = array_2.clone end # Combines two arrays with partial removal of duplicates # # @return [Array] of complate @array_1 and partially(removing the first # occurances in both arrays) added @array_2 def combine_outputs concat_arrays end 18 — @basthomas
do let(:array_1) do ['a', 'b', 'c'] end let(:array_2) do ['c', 'd', 'e'] end it 'concat the array in the right way' do expected_result = ['a', 'b', 'c', 'd', 'e'] expect(subject.combine_outputs).to match(expected_result) end let(:array_3) do ['x', 'y', 'z'] end it 'raises when cannot find similarities in array' do expect do described_class.new(array_1, array_3).combine_outputs end.to raise_exception('Cannot find comparable data') end end end 19 — @basthomas
arrays with removing the overlap between them # # @param existing [Array] the exsting elemets. # @param new_entries [Array] the elements that should be added to the front # @return [Array] returns the sum of both array with `new_entries` at the front def self.concat_without_overlap(existing, new_entries) occourences = new_entries.each_index.select { |i| new_entries.at(i) == existing.first } overlap_start = occourences.find { |index| array_starts_with?(existing, new_entries[index..-1]) } raise NoOverlapError, 'Cannot find comparable data' if overlap_start.nil? new_entries.first(overlap_start) + existing end # Checks if one array starts with an other one # # @param a1 [Array] the first array # @param a2 [Array] the second array # @return [Boolean] returns true if `a1` starts with `a2` def self.array_starts_with?(a1, a2) a1[0, a2.length] == a2 end end 20 — @basthomas
arrays with removing the overlap between them # # @param existing [Array] the exsting elemets. # @param new_entries [Array] the elements that should be # added to the front # @return [Array] returns the sum of both array with # `new_entries` at the front def self.concat_without_overlap(existing, new_entries) # implementation end end 22 — @basthomas
array to end of an existing one # without adding the overlap twice. # # @example # existing_entries = [1, 2, 3, 4] # new_entries = [4, 5, 6, 7] # Lists.stitch(existing_entries, new_entries) # => [1, 2, 3, 4, 5, 6, 7] # # @note Raises an NoOverlapError if no overlap is found. # # @param existing_entries [Array] the existing array. # @param new_entries [Array] the array to stitch to the existing one. # @return [Array] returns the new array def self.stitch(existing_entries, new_entries) # get the index of all occurrences of the first element from the # new_entries array in existing_entries occurrences = existing_entries.each_index .select { |i| existing_entries.at(i) == new_entries.first } # check if one of the slices of existing_entries is prefix of # the new_entries array overlap_start = occurrences .find { |index| array_starts_with?(new_entries, existing_entries[index..-1]) } raise NoOverlapError, 'Cannot find comparable data' if overlap_start.nil? # add the new_entries without the overlap at the end of the existing array existing_entries.first(overlap_start) + new_entries end 24 — @basthomas
/// - Parameter color: the text color to use. Available colors are a subset /// of `XINGColor` and are safe to use for text. /// - Parameter weight: the text weight to use. This will be used for the text's font. /// - Parameter size: the text size to use. This will be used for the text's font. /// - Parameter numberOfLines: The number of lines of text to render. /// To remove any maximum limit, and use as many lines as needed, /// set the value of this property to 0. @objc public init( color: TextColor, weight: TextWeight, size: TextSize, numberOfLines: Int ) { self._color = color self.weight = weight self.size = size self.numberOfLines = numberOfLines } 45 — @basthomas
configuration from. /// /// - Returns: a `TextConfiguration` based on the label, if it uses valid /// text configuration values. If not, it will assert and revert to default options. @objc public static func from(label: UILabel) -> TextConfiguration { func textColor(from color: UIColor) -> TextColor { guard let _textColor = TextColor.all.first(where: { $0.uiColor == label.textColor }) else { assertionFailure("Could not convert label's color to a valid TextColor. This will default to `.grey800` in production, which may be unexpected.") return .grey800 } return _textColor } func textWeight(from font: UIFont) -> TextWeight { guard let _textStyle = TextWeight.from(font: font) else { assertionFailure("Could not convert font's weight to a valid TextWeight. This will default to `.regular` in production, which may be unexpected.") return .regular } return _textStyle } func textSize(from font: UIFont) -> TextSize { guard let _textSize = TextSize.from(font: font) else { assertionFailure("Could not convert font's size to a valid TextSize. This will default to `.default12` in production, which may be unexpected.") return .default12 } return _textSize } return .init( color: textColor(from: label.textColor), weight: textWeight(from: label.font), size: textSize(from: label.font), numberOfLines: label.numberOfLines ) } 47 — @basthomas
/// - Parameter label: the `UILabel` instance to apply the /// text configuration to. /// /// - Returns: a reference to the label that has the configuration /// aplied to it. @discardableResult @objc public func apply(to label: UILabel) -> UILabel { label.textColor = color label.font = font label.numberOfLines = numberOfLines return label } 50 — @basthomas
fixed / covered during development) → Objective-C interop → Chainable API → It's not perfect (and that is OK) → Architecture design is missing 52 — @basthomas
Don't be afraid to use types → The compiler is your enemy → We should explain the architectural design → Prevent "rest of the damn owl" syndrom → Use assertions! 53 — @basthomas
write the correct code. There is no correct code. There is no silver bullet. → I want to help the most correct code to be written. → I want to prevent incorrect code to be written. → I want to fail early and often. → (but for that, I need it to be testable) → Iterate, iterate, iterate 54 — @basthomas
together and bounce off ideas → Documentation is helpful for yourself when writing code, too → Documentation helps you with naming, scope, testability and readability → Having testable code feels awesome → Snapshot tests are the root of all evil 55 — @basthomas
Conal Elliot https://github.com/conal/talk-2014-lambdajam-denotational-design "... But That Should Work?" by me https://basthomas.github.io/but-that-should-work Point-Free by Brandon Williams & Stephen Celis https://www.pointfree.co 57 — @basthomas