codeless_code 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +1 -1
  3. data/.reek.yml +14 -0
  4. data/.rubocop.yml +18 -0
  5. data/.ruby-version +1 -0
  6. data/{test/test_codeless_code.rb → .travis.yml} +12 -10
  7. data/Gemfile +5 -0
  8. data/Gemfile.lock +21 -0
  9. data/Guardfile +13 -1
  10. data/README.md +6 -0
  11. data/Rakefile +26 -11
  12. data/VERSION +1 -1
  13. data/bin/codeless_code +3 -1
  14. data/codeless_code.gemspec +33 -12
  15. data/lib/codeless_code/catalog.rb +3 -1
  16. data/lib/codeless_code/cli.rb +56 -24
  17. data/lib/codeless_code/commands/filter_fables.rb +15 -10
  18. data/lib/codeless_code/commands/list_translations.rb +3 -0
  19. data/lib/codeless_code/fable.rb +42 -53
  20. data/lib/codeless_code/fable_set.rb +8 -6
  21. data/lib/codeless_code/filters/builders.rb +4 -2
  22. data/lib/codeless_code/filters/composite.rb +3 -1
  23. data/lib/codeless_code/filters/date.rb +40 -30
  24. data/lib/codeless_code/filters/from_options.rb +45 -28
  25. data/lib/codeless_code/filters/headers/base.rb +61 -0
  26. data/lib/codeless_code/filters/{header_integer.rb → headers/integer.rb} +16 -19
  27. data/lib/codeless_code/filters/{header_string.rb → headers/string.rb} +12 -22
  28. data/lib/codeless_code/filters/lang.rb +3 -0
  29. data/lib/codeless_code/filters/translator.rb +7 -2
  30. data/lib/codeless_code/filters.rb +16 -8
  31. data/lib/codeless_code/formats/base.rb +20 -7
  32. data/lib/codeless_code/formats/parsers/base.rb +106 -0
  33. data/lib/codeless_code/formats/parsers/plain.rb +49 -0
  34. data/lib/codeless_code/formats/parsers/term.rb +79 -0
  35. data/lib/codeless_code/formats/plain.rb +21 -12
  36. data/lib/codeless_code/formats/raw.rb +2 -0
  37. data/lib/codeless_code/formats/term.rb +21 -15
  38. data/lib/codeless_code/language_set.rb +7 -4
  39. data/lib/codeless_code/options.rb +5 -3
  40. data/lib/codeless_code/renderers/fable.rb +13 -8
  41. data/lib/codeless_code/renderers/term_page.rb +46 -31
  42. data/lib/codeless_code.rb +119 -106
  43. data/test/codeless_code/commands/test_filter_fables.rb +89 -0
  44. data/test/codeless_code/filters/headers/test_integer.rb +86 -0
  45. data/test/codeless_code/filters/headers/test_string.rb +86 -0
  46. data/test/codeless_code/filters/test_builders.rb +4 -2
  47. data/test/codeless_code/filters/test_composite.rb +70 -0
  48. data/test/codeless_code/filters/test_date.rb +99 -0
  49. data/test/codeless_code/filters/test_langs.rb +50 -0
  50. data/test/codeless_code/filters/test_translator.rb +51 -0
  51. data/test/codeless_code/renderers/test_fable.rb +98 -0
  52. data/test/codeless_code/renderers/test_term_page.rb +87 -0
  53. data/test/codeless_code/test_catalog.rb +12 -5
  54. data/test/codeless_code/test_cli.rb +85 -0
  55. data/test/codeless_code/test_fable.rb +19 -10
  56. data/test/codeless_code/test_fable_set.rb +17 -5
  57. data/test/codeless_code/test_language_set.rb +16 -3
  58. data/test/codeless_code/test_options.rb +3 -11
  59. data/test/helper.rb +36 -10
  60. data/test/support/fs.rb +103 -0
  61. metadata +65 -11
  62. data/.document +0 -5
  63. data/data/README.md +0 -34
  64. data/lib/codeless_code/formats/plain_generator.rb +0 -157
  65. data/lib/codeless_code/formats/term_generator.rb +0 -167
  66. data/test/codeless_code/filters/test_header_integer.rb +0 -82
  67. data/test/codeless_code/filters/test_header_string.rb +0 -82
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # codeless_code filters and prints fables from http://thecodelesscode.com
2
4
  # Copyright (C) 2018 Jon Sangster
3
5
  #
@@ -23,27 +25,43 @@ module CodelessCode
23
25
 
24
26
  HEADER_PATTERN = /([^:\s]+)\s*:\s*(.+)\s*$/.freeze
25
27
 
26
- attr_reader :file, :read_headers
28
+ RAW_ATTRS = %w[Title Tagline Credits].freeze
29
+ INTEGER_ATTRS = %w[Number Geekiness].freeze
30
+ LIST_ATTRS = %w[Names Topics].freeze
31
+
32
+ attr_reader :file, :has_read_headers
27
33
 
28
- alias_method :read_headers?, :read_headers
34
+ alias read_headers? has_read_headers
29
35
  def_delegators :headers, :[], :fetch, :key?
30
36
 
31
37
  def initialize(file)
32
38
  @file = file
33
- @read_headers = false
34
- @body_pos = nil
39
+ @has_read_headers = false
40
+ @body_pos = 0
35
41
  end
36
42
 
37
43
  # @return [String] the actual story, including MediaWiki markup
38
44
  def body
39
45
  @body ||= read_body.freeze
40
46
  end
41
- alias_method :to_s, :body
47
+ alias to_s body
48
+
49
+ # Read, or re-read, the body of the fable from the disk
50
+ # @see #body
51
+ def read_body
52
+ headers unless read_headers?
53
+
54
+ io = file.open
55
+ io.seek @body_pos
56
+ io.read.strip
57
+ ensure
58
+ io&.close
59
+ end
42
60
 
43
61
  # @return [Hash<String, String>] the story's metadata
44
62
  def headers
45
63
  @headers ||= begin
46
- @read_headers = true
64
+ @has_read_headers = true
47
65
  read_headers.freeze
48
66
  end
49
67
  end
@@ -52,11 +70,6 @@ module CodelessCode
52
70
  headers.key?(key)
53
71
  end
54
72
 
55
- # @return [::Date, nil]
56
- def date
57
- ::Date.parse(self['Date']) if header?('Date')
58
- end
59
-
60
73
  # @return [Symbol]
61
74
  def lang
62
75
  @lang ||= dir_parts.first.to_sym
@@ -66,70 +79,46 @@ module CodelessCode
66
79
  @translator ||= dir_parts.last
67
80
  end
68
81
 
69
- def title
70
- self['Title']
71
- end
72
-
73
- def tagline
74
- self['Tagline']
82
+ RAW_ATTRS.each do |attr|
83
+ define_method(attr.downcase.to_sym) { self[attr] }
75
84
  end
76
85
 
77
- def credits
78
- self['Credits']
86
+ INTEGER_ATTRS.each do |attr|
87
+ define_method(attr.downcase.to_sym) { self[attr].to_i }
79
88
  end
80
89
 
81
- def number
82
- self['Number'].to_i
83
- end
84
-
85
- def geekiness
86
- self['Geekiness'].to_i
87
- end
88
-
89
- def names
90
- list('Names')
91
- end
92
-
93
- def topics
94
- list('Topics')
90
+ LIST_ATTRS.each do |attr|
91
+ define_method(attr.downcase.to_sym) { list(attr) }
95
92
  end
96
93
 
97
94
  private
98
95
 
99
- def read_body
100
- headers unless read_headers?
101
-
96
+ def read_headers
102
97
  io = file.open
103
- io.seek @body_pos
104
- io.read.strip
98
+ parse_headers(io)
105
99
  ensure
106
100
  io&.close
107
101
  end
108
102
 
109
- def read_headers
110
- io = file.open
103
+ # :reek:FeatureEnvy
104
+ def parse_headers(io, head = {})
105
+ until io.eof?
106
+ @body_pos = io.pos
107
+ match = HEADER_PATTERN.match(io.gets)
108
+ break if match.nil?
111
109
 
112
- {}.tap do |head|
113
- until io.eof?
114
- @body_pos = io.pos
115
- if (m = HEADER_PATTERN.match(io.gets))
116
- head[m[1].strip] = m[2]&.strip
117
- else
118
- break
119
- end
120
- end
121
-
122
- massage_headers(head)
110
+ head[match[1].strip] = match[2]&.strip
123
111
  end
124
- ensure
125
- io&.close
112
+ massage_headers(head)
126
113
  end
127
114
 
115
+ # :reek:UtilityFunction
128
116
  def massage_headers(head)
129
117
  if head.key?('Series')
130
118
  head['Series'] = head['Title']
131
119
  head['Title'] = head.delete('Subtitle')
132
120
  end
121
+ head
133
122
  end
134
123
 
135
124
  def list(key)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # codeless_code filters and prints fables from http://thecodelesscode.com
2
4
  # Copyright (C) 2018 Jon Sangster
3
5
  #
@@ -22,14 +24,14 @@ module CodelessCode
22
24
  extend Forwardable
23
25
  include Enumerable
24
26
 
25
- FILE_PATTERN = '*.txt'.freeze
26
- LANG_SEP = '-'.freeze
27
+ FILE_PATTERN = '*.txt'
28
+ LANG_SEP = '-'
27
29
 
28
- attr_accessor :dir
30
+ attr_reader :dir
29
31
  def_delegator :fables, :each
30
32
 
31
33
  def initialize(dir)
32
- self.dir = dir
34
+ @dir = dir
33
35
  end
34
36
 
35
37
  def lang
@@ -41,11 +43,11 @@ module CodelessCode
41
43
  end
42
44
 
43
45
  def fables
44
- @fables ||= files.map { |f| Fable.new(f) }.sort_by(&:number)
46
+ @fables ||= files.map { |file| Fable.new(file) }.sort_by(&:number)
45
47
  end
46
48
 
47
49
  def filter(filt)
48
- select { |f| filt.call(f) }
50
+ select { |fable| filt.call(fable) }
49
51
  end
50
52
 
51
53
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # codeless_code filters and prints fables from http://thecodelesscode.com
2
4
  # Copyright (C) 2018 Jon Sangster
3
5
  #
@@ -20,11 +22,11 @@ module CodelessCode
20
22
  module_function
21
23
 
22
24
  def header_integer_filter(name)
23
- subclass_filter(HeaderInteger, name)
25
+ subclass_filter(Headers::Integer, name)
24
26
  end
25
27
 
26
28
  def header_string_filter(name)
27
- subclass_filter(HeaderString, name)
29
+ subclass_filter(Headers::String, name)
28
30
  end
29
31
 
30
32
  def subclass_filter(klass, name)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # codeless_code filters and prints fables from http://thecodelesscode.com
2
4
  # Copyright (C) 2018 Jon Sangster
3
5
  #
@@ -35,7 +37,7 @@ module CodelessCode
35
37
  end
36
38
 
37
39
  def call(fable)
38
- select(&:enabled?).all? { |filter| filter.call(fable) }
40
+ any? && select(&:enabled?).all? { |filter| filter.call(fable) }
39
41
  end
40
42
  end
41
43
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # codeless_code filters and prints fables from http://thecodelesscode.com
2
4
  # Copyright (C) 2018 Jon Sangster
3
5
  #
@@ -17,43 +19,40 @@ require 'date'
17
19
 
18
20
  module CodelessCode
19
21
  module Filters
20
- class Date
22
+ # Matches {Fable fables} that were published on, before, or after a given
23
+ # date.
24
+ class Date < Headers::Base
25
+ # :reek:BooleanParameter
21
26
  def initialize(exact: nil, min: nil, max: nil, exclude: false)
22
- @exact = exact
23
- @min = min
24
- @max = max
25
- @exclude = exclude
27
+ super('Date', exclude, [Matcher.parse(exact), :==],
28
+ [Matcher.parse(min), :<=],
29
+ [Matcher.parse(max), :>=])
26
30
  end
27
31
 
28
- def enabled?
29
- @exact || @min || @max || @exclude
32
+ # :reek:UtilityFunction
33
+ def parse(val)
34
+ ::Date.parse(val)
30
35
  end
31
36
 
32
- def call(fable)
33
- if (val = fable.date)
34
- return false unless @exact.nil? || @exact == val
35
- return false unless @min.nil? || @min <= val
36
- return false unless @max.nil? || @max >= val
37
- true
38
- else
39
- @exclude
40
- end
37
+ def test_single(val, operator, test)
38
+ test.send(operator, val)
41
39
  end
42
40
 
41
+ # Wraps a {::Date} and matches it against "date substrings". ie:
42
+ # +2010-12+ will matches any dates in December, 2010 and +2010+ will
43
+ # match any dates in that year.
43
44
  class Matcher
44
45
  # param str [String] A date like +2010+, +2010-12+, or +2010-12-23+
45
46
  def self.parse(str)
46
- match = :day
47
+ return nil unless str
47
48
 
48
49
  if str.size == 4
49
- str = "#{str}-01-01"
50
- match = :year
50
+ new(::Date.parse("#{str}-01-01"), match: :year)
51
51
  elsif str.size == 7
52
- str = "#{str}-01"
53
- match = :month
52
+ new(::Date.parse("#{str}-01"), match: :month)
53
+ else
54
+ new(::Date.parse(str), match: :day)
54
55
  end
55
-
56
- new(::Date.parse(str), match: match)
57
56
  end
58
57
 
59
58
  def initialize(date, match:)
@@ -62,27 +61,38 @@ module CodelessCode
62
61
  end
63
62
 
64
63
  def ==(other)
65
- cmp(@date, other, :==, @match)
64
+ compare(@date, other, :==, @match)
66
65
  end
67
66
 
68
67
  def >=(other)
69
- cmp(@date, other, :>=, @match)
68
+ compare(@date, other, :>=, @match)
70
69
  end
71
70
 
72
71
  def <=(other)
73
- cmp(@date, other, :<=, @match)
72
+ compare(@date, other, :<=, @match)
74
73
  end
75
74
 
76
75
  private
77
76
 
78
- def cmp(a, b, op, match)
77
+ # :reek:ControlParameter
78
+ # :reek:FeatureEnvy
79
+ def compare(first, second, operator, match)
79
80
  case match
80
81
  when :year
81
- a.year.send(op, b.year)
82
+ first.year.send(operator, second.year)
82
83
  when :month
83
- a.year == b.year ? a.month.send(op, b.month) : cmp(a, b, op, :year)
84
+ compare_month(first, second, operator)
85
+ else
86
+ first.send(operator, second)
87
+ end
88
+ end
89
+
90
+ # :reek:FeatureEnvy
91
+ def compare_month(first, second, operator)
92
+ if first.year == second.year
93
+ first.month.send(operator, second.month)
84
94
  else
85
- a.send(op, b)
95
+ compare(first, second, operator, :year)
86
96
  end
87
97
  end
88
98
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # codeless_code filters and prints fables from http://thecodelesscode.com
2
4
  # Copyright (C) 2018 Jon Sangster
3
5
  #
@@ -37,28 +39,46 @@ module CodelessCode
37
39
  end
38
40
 
39
41
  def filters
40
- @filters ||= [
41
- Filters::Lang.new(exact: lang),
42
+ @filters ||=
43
+ string_filters +
44
+ integer_filters +
45
+ [
46
+ filter(:Date, :date),
47
+ new_filter(:Lang, exact: lang),
48
+ number_filter,
49
+ translator_filter
50
+ ]
51
+ end
42
52
 
43
- Filters::Translator.new(exact: @opts[:translator_exact],
44
- casecmp: @opts[:translator]),
53
+ private
45
54
 
46
- Filters::Credits.new(**str_args(:credits)),
47
- Filters::Name.new(**str_args(:name)),
48
- Filters::Series.new(**str_args(:series)),
49
- Filters::Tagline.new(**str_args(:tagline)),
50
- Filters::Title.new(**str_args(:title)),
55
+ def string_filters
56
+ %i[Credits Name Tagline Title Series].map { |name| filter(name, :str) }
57
+ end
51
58
 
52
- Filters::Geekiness.new(**int_args(:geekiness)),
53
- Filters::Number.new(**int_args(:number).tap do |n|
54
- n[:exact] ||= @opts.args.last&.to_i
55
- end),
59
+ def integer_filters
60
+ %i[Geekiness].map { |name| filter(name, :int) }
61
+ end
56
62
 
57
- Filters::Date.new(**date_args),
58
- ]
63
+ def number_filter
64
+ filter(:Number, :int) { |args| args[:exact] ||= @opts.args.last&.to_i }
59
65
  end
60
66
 
61
- private
67
+ def translator_filter
68
+ new_filter(:Translator, exact: @opts[:translator_exact],
69
+ casecmp: @opts[:translator])
70
+ end
71
+
72
+ def filter(name, type, &blk)
73
+ new_filter(name,
74
+ **send(:"#{type.downcase}_args", name.to_s.downcase.to_s),
75
+ &blk)
76
+ end
77
+
78
+ def new_filter(name, **args)
79
+ yield args if block_given?
80
+ Filters.const_get(name).new(**args)
81
+ end
62
82
 
63
83
  def fallback_lang
64
84
  lang = ENV['LANG']&.split(/_|\./)&.first&.downcase&.to_sym
@@ -66,13 +86,14 @@ module CodelessCode
66
86
  end
67
87
 
68
88
  def non_defaults_enabled?
69
- filters.reject { |f| f.is_a?(Filters::Lang) }.any?(&:enabled?)
89
+ filters.reject { |filter| filter.is_a?(Filters::Lang) }.any?(&:enabled?)
70
90
  end
71
91
 
72
92
  def str_args(name)
73
93
  Hash[
74
94
  %i[exact start_with end_with exclude].zip(
75
- @opts.slice(*%I[#{name} #{name}_start #{name}_end no_#{name}]).values
95
+ @opts.slice(:"#{name}", :"#{name}_start", :"#{name}_end",
96
+ :"no_#{name}").values
76
97
  )
77
98
  ].tap do |args|
78
99
  args[:start_with] ||= '' if @opts[:"has_#{name}"]
@@ -82,7 +103,7 @@ module CodelessCode
82
103
  def int_args(name)
83
104
  Hash[
84
105
  %i[exact min max exclude].zip(
85
- @opts.slice(*%I[#{name} #{name}_gte #{name}_lte])
106
+ @opts.slice(:"#{name}", :"#{name}_gte", :"#{name}_lte")
86
107
  .values
87
108
  .map { |num| num&.to_i }
88
109
  .push(@opts[:"no_#{name}"])
@@ -90,18 +111,14 @@ module CodelessCode
90
111
  ]
91
112
  end
92
113
 
93
- def date_args
114
+ def date_args(name)
94
115
  {
95
- exact: date(@opts[:date]),
96
- min: date(@opts[:date_gte]),
97
- max: date(@opts[:date_lte]),
98
- exclude: @opts[:no_date],
116
+ exact: @opts[:"#{name}"],
117
+ min: @opts[:"#{name}_after"],
118
+ max: @opts[:"#{name}_before"],
119
+ exclude: @opts[:"no_#{name}"]
99
120
  }
100
121
  end
101
-
102
- def date(arg)
103
- arg && Filters::Date::Matcher.parse(arg)
104
- end
105
122
  end
106
123
  end
107
124
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ # codeless_code filters and prints fables from http://thecodelesscode.com
4
+ # Copyright (C) 2018 Jon Sangster
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify it under
7
+ # the terms of the GNU General Public License as published by the Free Software
8
+ # Foundation, either version 3 of the License, or (at your option) any later
9
+ # version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
+ # details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License along with
17
+ # this program. If not, see <https://www.gnu.org/licenses/>.
18
+ module CodelessCode
19
+ module Filters
20
+ module Headers
21
+ # Abstract base class for all generic filters that test a {Fable fable's}
22
+ # headers.
23
+ class Base
24
+ def initialize(key, exclude, *tests)
25
+ @key = key
26
+ @exclude = exclude
27
+ @tests ||= tests.select(&:first).freeze
28
+ end
29
+
30
+ def enabled?
31
+ @tests.any? || @exclude
32
+ end
33
+
34
+ def call(fable)
35
+ if fable.header?(@key)
36
+ @tests.any? ? test(parse(fable[@key])) : !@exclude
37
+ else
38
+ @exclude
39
+ end
40
+ end
41
+
42
+ protected
43
+
44
+ # :reek:UtilityFunction
45
+ def parse(val)
46
+ val
47
+ end
48
+
49
+ def test_single(val, operator, test)
50
+ val.send(operator, test)
51
+ end
52
+
53
+ private
54
+
55
+ def test(val)
56
+ @tests.any? { |(test, op)| test_single(val, op, test) }
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # codeless_code filters and prints fables from http://thecodelesscode.com
2
4
  # Copyright (C) 2018 Jon Sangster
3
5
  #
@@ -15,27 +17,22 @@
15
17
  # this program. If not, see <https://www.gnu.org/licenses/>.
16
18
  module CodelessCode
17
19
  module Filters
18
- class HeaderInteger
19
- def initialize(key, exact: nil, min: nil, max: nil, exclude: false)
20
- @key = key
21
- @exact = exact
22
- @min = min
23
- @max = max
24
- @exclude = exclude
25
- end
20
+ module Headers
21
+ # Matches {Fable fables} that have an integer header equal to, less than,
22
+ # or greater than the given parameters.
23
+ class Integer < Base
24
+ # :reek:BooleanParameter
25
+ def initialize(key, exact: nil, min: nil, max: nil, exclude: false)
26
+ super(key, exclude, [exact, :==],
27
+ [min, :>=],
28
+ [max, :<=])
29
+ end
26
30
 
27
- def enabled?
28
- @exact || @min || @max || @exclude
29
- end
31
+ protected
30
32
 
31
- def call(fable)
32
- if fable.header?(@key) && (val = fable[@key]&.to_i)
33
- return false unless @exact.nil? || val == @exact
34
- return false unless @min.nil? || val >= @min.to_i
35
- return false unless @max.nil? || val <= @max.to_i
36
- !@exclude
37
- else
38
- @exclude
33
+ # :reek:UtilityFunction
34
+ def parse(val)
35
+ val.to_i
39
36
  end
40
37
  end
41
38
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # codeless_code filters and prints fables from http://thecodelesscode.com
2
4
  # Copyright (C) 2018 Jon Sangster
3
5
  #
@@ -15,28 +17,16 @@
15
17
  # this program. If not, see <https://www.gnu.org/licenses/>.
16
18
  module CodelessCode
17
19
  module Filters
18
- class HeaderString
19
- def initialize(key, exact: nil, start_with: nil, end_with: nil,
20
- exclude: false)
21
- @key = key
22
- @exact = exact
23
- @start_with = start_with
24
- @end_with = end_with
25
- @exclude = exclude
26
- end
27
-
28
- def enabled?
29
- @exact || @start_with || @end_with || @exclude
30
- end
31
-
32
- def call(fable)
33
- if fable.header?(@key) && (val = fable[@key])
34
- return false unless @exact.nil? || val == @exact
35
- return false unless @start_with.nil? || val.start_with?(@start_with)
36
- return false unless @end_with.nil? || val.end_with?(@end_with)
37
- !@exclude
38
- else
39
- @exclude
20
+ module Headers
21
+ # Matches {Fable fables} that have an string header equal to, that starts
22
+ # with, or ends with the given parameters.
23
+ class String < Base
24
+ # :reek:BooleanParameter
25
+ def initialize(key, exact: nil, start_with: nil, end_with: nil,
26
+ exclude: false)
27
+ super(key, exclude, [exact, :==],
28
+ [start_with, :start_with?],
29
+ [end_with, :end_with?])
40
30
  end
41
31
  end
42
32
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # codeless_code filters and prints fables from http://thecodelesscode.com
2
4
  # Copyright (C) 2018 Jon Sangster
3
5
  #
@@ -15,6 +17,7 @@
15
17
  # this program. If not, see <https://www.gnu.org/licenses/>.
16
18
  module CodelessCode
17
19
  module Filters
20
+ # Matches {Fable fables} in the given language (code).
18
21
  class Lang
19
22
  def initialize(exact: nil)
20
23
  @exact = exact
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # codeless_code filters and prints fables from http://thecodelesscode.com
2
4
  # Copyright (C) 2018 Jon Sangster
3
5
  #
@@ -15,6 +17,7 @@
15
17
  # this program. If not, see <https://www.gnu.org/licenses/>.
16
18
  module CodelessCode
17
19
  module Filters
20
+ # Matches {Fable fables} translated by the person with the given name.
18
21
  class Translator
19
22
  def initialize(exact: nil, casecmp: nil)
20
23
  @exact = exact
@@ -26,8 +29,10 @@ module CodelessCode
26
29
  end
27
30
 
28
31
  def call(fable)
29
- return false unless @exact.nil? || @exact == fable.translator
30
- @casecmp.nil? || @casecmp.casecmp?(fable.translator)
32
+ trans = fable.translator
33
+ return false unless @exact.nil? || @exact == trans
34
+
35
+ @casecmp.nil? || @casecmp.casecmp?(trans)
31
36
  end
32
37
  end
33
38
  end