redi_search 1.0.0 → 1.0.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0666cc15e7fc7d132026337c916b5d233114d65378ff172d9a48ae81ed1a9eae
4
- data.tar.gz: 575c1230885537ea9a31b753808894d187f00718fe8d0fca282cba426b75e0c8
3
+ metadata.gz: 28b67b5a88b3440ae45548484cc556a2cc0866328701f3a0ae8bac9aee8fe0c4
4
+ data.tar.gz: 494003de36b2acfd5b0338dc2421dd1add923d55ac0925f1ae2f798f0d56f535
5
5
  SHA512:
6
- metadata.gz: 0f1486c6d2a7b1a726d6c956398e693317df4efffa0c73e45b180a3acb2ac36b69284e68e3230862e6948015b1ceee0a1ac518dab6182c86e4b2c710f587cd16
7
- data.tar.gz: c9e179c20fc545612a00fd2f9b46e5a2eae9ce1292d4635625a80abf641d726d248ee753633dfa8e292b0dba1543af410e58cf5a10380d7854c66af2c06326a1
6
+ metadata.gz: cf672f8b0c8ac5b129c36596c24bfcbbb0eb522c7b8233d24b5b6f68ccf4465989e298c2fef25ed355a9ab476159ffd2682bf622bc10df8625b46a641005633c
7
+ data.tar.gz: 319e401ec3cf9ac165c62e84223c62e267bd80658bdf61abcbf673d87a51516a6de8f02c51441d3b355fdd03fddf479c5e6ae5aa86002e7503bc62f33e32422f
@@ -35,15 +35,8 @@ module RediSearch
35
35
  attr_reader :index, :document, :score, :replace, :language, :no_save
36
36
 
37
37
  def command
38
- [
39
- "ADD",
40
- index.name,
41
- document.document_id,
42
- score,
43
- *extract_options,
44
- "FIELDS",
45
- document.redis_attributes
46
- ].compact
38
+ ["ADD", index.name, document.document_id, score, *extract_options,
39
+ "FIELDS", document.redis_attributes].compact
47
40
  end
48
41
 
49
42
  def extract_options
@@ -10,12 +10,9 @@ module RediSearch
10
10
 
11
11
  def call!
12
12
  index.schema.alter(field_name, raw_schema)
13
+
13
14
  RediSearch.client.call!(
14
- "ALTER",
15
- index.name,
16
- "SCHEMA",
17
- "ADD",
18
- *field_schema
15
+ "ALTER", index.name, "SCHEMA", "ADD", *field_schema
19
16
  ).ok?
20
17
  end
21
18
 
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RediSearch
4
+ class Client
5
+ class Response < SimpleDelegator
6
+ def initialize(response)
7
+ @response = response
8
+
9
+ super(response)
10
+ end
11
+
12
+ def ok?
13
+ case response
14
+ when String then response == "OK"
15
+ when Integer then response == 1
16
+ when Array then array_ok?
17
+ else response
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :response
24
+
25
+ def array_ok?
26
+ response.all? do |pipeline_response|
27
+ Response.new(pipeline_response).ok?
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,31 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "redis"
4
+ require "redi_search/client/response"
4
5
 
5
6
  module RediSearch
6
7
  class Client
7
- class Response < SimpleDelegator
8
- def initialize(response)
9
- @response = response
10
-
11
- super(response)
12
- end
13
-
14
- def ok?
15
- if response.is_a? String
16
- response == "OK"
17
- elsif response.is_a? Array
18
- response.all? { |pipeline_response| pipeline_response == "OK" }
19
- else
20
- response
21
- end
22
- end
23
-
24
- private
25
-
26
- attr_reader :response
27
- end
28
-
29
8
  def initialize(redis_config)
30
9
  @redis = Redis.new(redis_config)
31
10
  end
@@ -52,16 +31,11 @@ module RediSearch
52
31
  Response.new(redis.call("FT.#{command}", *params))
53
32
  end
54
33
 
55
- def instrument(action, payload)
56
- block =
57
- if block_given?
58
- Proc.new
59
- else
60
- proc {}
61
- end
62
-
34
+ def instrument(action, payload, &block)
63
35
  ActiveSupport::Notifications.instrument(
64
- "#{action}.redi_search", { name: "RediSearch" }.merge(payload), &block
36
+ "#{action}.redi_search",
37
+ { name: "RediSearch" }.merge(payload),
38
+ &Proc.new(&(block || proc {}))
65
39
  )
66
40
  end
67
41
  end
@@ -18,11 +18,7 @@ module RediSearch
18
18
 
19
19
  def call!
20
20
  RediSearch.client.call!(
21
- "CREATE",
22
- index.name,
23
- *extract_options.compact,
24
- "SCHEMA",
25
- schema.to_a
21
+ "CREATE", index.name, *extract_options.compact, "SCHEMA", schema.to_a
26
22
  ).ok?
27
23
  end
28
24
 
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RediSearch
4
+ class Document
5
+ module Display
6
+ #:nocov:
7
+ def inspect
8
+ inspection = pretty_print_attributes.map do |field_name|
9
+ "#{field_name}: #{public_send(field_name)}"
10
+ end.compact.join(", ")
11
+
12
+ "#<#{self.class} #{inspection}>"
13
+ end
14
+
15
+ def pretty_print(printer) # rubocop:disable Metrics/MethodLength
16
+ printer.object_address_group(self) do
17
+ printer.seplist(
18
+ pretty_print_attributes , proc { printer.text "," }
19
+ ) do |field_name|
20
+ printer.breakable " "
21
+ printer.group(1) do
22
+ printer.text field_name
23
+ printer.text ":"
24
+ printer.breakable
25
+ printer.pp public_send(field_name)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ def pretty_print_attributes
32
+ pp_attrs = attributes.keys.dup
33
+ pp_attrs.push("document_id")
34
+ pp_attrs.push("score") if score.present?
35
+
36
+ pp_attrs.compact
37
+ end
38
+ #:nocov:
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RediSearch
4
+ class Document
5
+ class Finder
6
+ def initialize(index, *document_ids)
7
+ @index = index
8
+ @document_ids = Array.wrap(document_ids)
9
+ end
10
+
11
+ def find
12
+ if multi?
13
+ parse_multi_documents
14
+ else
15
+ parse_document(document_ids.first, response)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :index, :document_ids
22
+
23
+ def response
24
+ @response ||= call!(get_command, index.name, *prepended_document_ids)
25
+ end
26
+
27
+ def call!(*command)
28
+ RediSearch.client.call!(*command)
29
+ end
30
+
31
+ def get_command
32
+ if multi?
33
+ "MGET"
34
+ else
35
+ "GET"
36
+ end
37
+ end
38
+
39
+ def multi?
40
+ document_ids.size > 1
41
+ end
42
+
43
+ def prepended_document_ids
44
+ document_ids.map do |document_id|
45
+ prepend_document_id(document_id)
46
+ end
47
+ end
48
+
49
+ def prepend_document_id(id)
50
+ if id.to_s.start_with? index.name
51
+ id
52
+ else
53
+ "#{index.name}#{id}"
54
+ end
55
+ end
56
+
57
+ def parse_multi_documents
58
+ document_ids.map.with_index do |document_id, index|
59
+ parse_document(document_id, response[index])
60
+ end.compact
61
+ end
62
+
63
+ def parse_document(document_id, document_response)
64
+ return if document_response.blank?
65
+
66
+ Document.new(index, document_id, Hash[*document_response])
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,7 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "redi_search/document/display"
4
+ require "redi_search/document/finder"
5
+
3
6
  module RediSearch
4
7
  class Document
8
+ include Display
9
+
5
10
  class << self
6
11
  def for_object(index, record, serializer: nil, only: [])
7
12
  object_to_serialize = serializer&.new(record) || record
@@ -16,34 +21,11 @@ module RediSearch
16
21
  end
17
22
 
18
23
  def get(index, document_id)
19
- response = RediSearch.client.call!(
20
- "GET", index.name, prepend_document_id(index, document_id)
21
- )
22
-
23
- return if response.blank?
24
-
25
- new(index, document_id, Hash[*response])
24
+ Finder.new(index, document_id).find
26
25
  end
27
26
 
28
27
  def mget(index, *document_ids)
29
- unique_document_ids = document_ids.map do |id|
30
- prepend_document_id(index, id)
31
- end
32
- document_ids.zip(
33
- RediSearch.client.call!("MGET", index.name, *unique_document_ids)
34
- ).map do |document|
35
- next if document[1].blank?
36
-
37
- new(index, document[0], Hash[*document[1]])
38
- end.compact
39
- end
40
-
41
- def prepend_document_id(index, document_id)
42
- if document_id.to_s.starts_with? index.name
43
- document_id
44
- else
45
- "#{index.name}#{document_id}"
46
- end
28
+ Finder.new(index, *document_ids).find
47
29
  end
48
30
  end
49
31
 
@@ -55,53 +37,12 @@ module RediSearch
55
37
  @attributes = fields
56
38
  @score = score
57
39
 
58
- attributes.each do |field, value|
59
- next unless schema_fields.include? field
60
-
61
- instance_variable_set(:"@#{field}", value)
62
- define_singleton_method(field) { value }
63
- end
40
+ load_attributes
64
41
  end
65
42
 
66
43
  def del(delete_document: false)
67
- client.call!(
68
- "DEL", index.name, document_id, ("DD" if delete_document)
69
- ) == 1
70
- end
71
-
72
- #:nocov:
73
- def inspect
74
- inspection = pretty_print_attributes.map do |field_name|
75
- "#{field_name}: #{public_send(field_name)}"
76
- end.compact.join(", ")
77
-
78
- "#<#{self.class} #{inspection}>"
79
- end
80
-
81
- def pretty_print(printer) # rubocop:disable Metrics/MethodLength
82
- printer.object_address_group(self) do
83
- printer.seplist(
84
- pretty_print_attributes , proc { printer.text "," }
85
- ) do |field_name|
86
- printer.breakable " "
87
- printer.group(1) do
88
- printer.text field_name
89
- printer.text ":"
90
- printer.breakable
91
- printer.pp public_send(field_name)
92
- end
93
- end
94
- end
95
- end
96
-
97
- def pretty_print_attributes
98
- pp_attrs = attributes.keys.dup
99
- pp_attrs.push("document_id")
100
- pp_attrs.push("score") if score.present?
101
-
102
- pp_attrs.compact
44
+ call!("DEL", index.name, document_id, ("DD" if delete_document)).ok?
103
45
  end
104
- #:nocov:
105
46
 
106
47
  def schema_fields
107
48
  @schema_fields ||= index.schema.fields.map(&:to_s)
@@ -112,7 +53,11 @@ module RediSearch
112
53
  end
113
54
 
114
55
  def document_id
115
- self.class.prepend_document_id(index, @document_id)
56
+ if @document_id.to_s.start_with? index.name
57
+ @document_id
58
+ else
59
+ "#{index.name}#{@document_id}"
60
+ end
116
61
  end
117
62
 
118
63
  def document_id_without_index
@@ -127,8 +72,17 @@ module RediSearch
127
72
 
128
73
  attr_reader :index
129
74
 
130
- def client
131
- RediSearch.client
75
+ def call!(*command)
76
+ RediSearch.client.call!(*command)
77
+ end
78
+
79
+ def load_attributes
80
+ attributes.each do |field, value|
81
+ next unless schema_fields.include? field
82
+
83
+ instance_variable_set(:"@#{field}", value)
84
+ define_singleton_method(field) { value }
85
+ end
132
86
  end
133
87
  end
134
88
  end
@@ -19,24 +19,26 @@ module RediSearch
19
19
  def to_a
20
20
  execute unless loaded?
21
21
 
22
- @documents
22
+ documents
23
23
  end
24
24
 
25
25
  alias load to_a
26
26
 
27
27
  #:nocov:
28
28
  def inspect
29
- execute unless loaded?
29
+ execute_and_rescue_inspection do
30
+ return super unless valid?
30
31
 
31
- to_a
32
+ documents
33
+ end
32
34
  end
33
35
 
34
36
  def pretty_print(printer)
35
- execute unless loaded?
37
+ execute_and_rescue_inspection do
38
+ return super(inspect) unless valid?
36
39
 
37
- printer.pp(documents)
38
- rescue Redis::CommandError => e
39
- printer.pp(e.message)
40
+ printer.pp(documents)
41
+ end
40
42
  end
41
43
  #:nocov:
42
44
 
@@ -51,15 +53,35 @@ module RediSearch
51
53
  end
52
54
 
53
55
  def execute
56
+ return unless valid?
57
+
54
58
  @loaded = true
55
59
 
56
- RediSearch.client.call!(*command).yield_self do |response|
60
+ call!(*command).yield_self do |response|
57
61
  parse_response(response)
58
62
  end
59
63
  end
60
64
 
65
+ def call!(*command)
66
+ RediSearch.client.call!(*command)
67
+ end
68
+
61
69
  def parse_response(_response)
62
70
  raise NotImplementedError, "included class did not define #{__method__}"
63
71
  end
72
+
73
+ def valid?
74
+ true
75
+ end
76
+
77
+ #:nocov:
78
+ def execute_and_rescue_inspection
79
+ execute unless loaded?
80
+
81
+ yield
82
+ rescue Redis::CommandError => e
83
+ e.message
84
+ end
85
+ #:nocov:
64
86
  end
65
87
  end
@@ -68,17 +68,19 @@ module RediSearch
68
68
  self.class.runtime += event.duration
69
69
  return unless logger.debug?
70
70
 
71
- payload = event.payload
72
- name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
73
- command = command_string(payload)
71
+ command = command_string(event)
74
72
 
75
- debug " #{color(name, RED, true)} #{color(command, debug_color, true)}"
73
+ debug " #{log_name(event)} #{color(command, debug_color, true)}"
76
74
  end
77
75
 
78
- def command_string(payload)
79
- payload[:query].flatten.map.with_index do |arg, i|
76
+ def log_name(event)
77
+ color("#{event.payload[:name]} (#{event.duration.round(1)}ms)", RED, true)
78
+ end
79
+
80
+ def command_string(event)
81
+ event.payload[:query].flatten.map.with_index do |arg, i|
80
82
  arg = "FT.#{arg}" if prepend_ft?(arg, i)
81
- arg = arg.inspect if inspect_arg?(payload, arg)
83
+ arg = arg.inspect if inspect_arg?(event.payload, arg)
82
84
  arg
83
85
  end.join(" ")
84
86
  end
@@ -12,9 +12,7 @@ module RediSearch
12
12
  schema, options = options.to_a.flatten
13
13
 
14
14
  "RediSearch::Schema::#{schema.to_s.capitalize}Field".
15
- constantize.
16
- new(field_name, **options.to_h).
17
- to_a
15
+ constantize.new(field_name, **options.to_h).to_a
18
16
  end
19
17
 
20
18
  def initialize(raw)
@@ -9,16 +9,13 @@ module RediSearch
9
9
  @prior_clause = prior_clause
10
10
  @not = false
11
11
 
12
- initialize_term(term, **term_options)
12
+ initialize_term(term, **term_options) if term.present?
13
13
  end
14
14
 
15
15
  def to_s
16
16
  raise ArgumentError, "missing query terms" if term.blank?
17
17
 
18
- [
19
- prior_clause.presence,
20
- queryify_term.dup.prepend(not_operator)
21
- ].compact.join(operand)
18
+ [prior_clause.presence, queryify_term].compact.join(operand)
22
19
  end
23
20
 
24
21
  delegate :inspect, to: :to_s
@@ -26,7 +23,7 @@ module RediSearch
26
23
  def not(term, **term_options)
27
24
  @not = true
28
25
 
29
- initialize_term(term, **term_options)
26
+ initialize_term(term, **term_options) if term.present?
30
27
 
31
28
  search
32
29
  end
@@ -46,25 +43,31 @@ module RediSearch
46
43
  end
47
44
 
48
45
  def initialize_term(term, **term_options)
49
- return if term.blank?
50
-
51
- @term =
52
- if term.is_a? RediSearch::Search
53
- term
54
- else
55
- Term.new(term, term_options)
56
- end
46
+ @term = if term.is_a? RediSearch::Search
47
+ term
48
+ else
49
+ Term.new(term, term_options)
50
+ end
57
51
  end
58
52
 
59
53
  def queryify_term
60
- if term.is_a?(RediSearch::Search) &&
61
- !term.term_clause.is_a?(RediSearch::Search::Clauses::Where)
62
- "(#{term.term_clause})"
63
- elsif term.is_a?(RediSearch::Search)
64
- term.term_clause
54
+ if term_is_search?
55
+ queryify_search
65
56
  else
66
57
  term
67
- end.to_s
58
+ end.to_s.dup.prepend(not_operator)
59
+ end
60
+
61
+ def term_is_search?
62
+ term.is_a? RediSearch::Search
63
+ end
64
+
65
+ def queryify_search
66
+ if !term.term_clause.is_a?(RediSearch::Search::Clauses::Where)
67
+ "(#{term.term_clause})"
68
+ else
69
+ term.term_clause
70
+ end
68
71
  end
69
72
  end
70
73
  end
@@ -53,12 +53,15 @@ module RediSearch
53
53
  condition, *options = condition.to_a
54
54
 
55
55
  @field = condition[0]
56
- @term =
57
- if condition[1].is_a? RediSearch::Search
58
- condition[1]
59
- else
60
- Term.new(condition[1], **options.to_h)
61
- end
56
+ @term = make_term(condition, options)
57
+ end
58
+
59
+ def make_term(condition, options)
60
+ if condition[1].is_a? RediSearch::Search
61
+ condition[1]
62
+ else
63
+ Term.new(condition[1], **options.to_h)
64
+ end
62
65
  end
63
66
  end
64
67
  end
@@ -66,13 +66,11 @@ module RediSearch
66
66
  end
67
67
 
68
68
  def count
69
- if @loaded
70
- to_a.size
71
- else
72
- RediSearch.client.call!(
73
- "SEARCH", index.name, term_clause, *Limit.new(total: 0).clause
74
- ).first
75
- end
69
+ return to_a.size if loaded?
70
+
71
+ call!(
72
+ "SEARCH", index.name, term_clause, *Limit.new(total: 0).clause
73
+ ).first
76
74
  end
77
75
 
78
76
  def where(**condition)
@@ -7,13 +7,7 @@ module RediSearch
7
7
  @count = count
8
8
  @used_clauses = used_clauses
9
9
 
10
- super(documents.each_slice(response_slice).map do |slice|
11
- document_id = slice[0]
12
- fields = slice.last unless no_content?
13
- score = slice[1].to_f if with_scores?
14
-
15
- Document.new(index, document_id, Hash[*fields.to_a], score)
16
- end)
10
+ super(parse_results(index, documents))
17
11
  end
18
12
 
19
13
  def count
@@ -41,6 +35,16 @@ module RediSearch
41
35
  def no_content?
42
36
  @used_clauses.include? "no_content"
43
37
  end
38
+
39
+ def parse_results(index, documents)
40
+ documents.each_slice(response_slice).map do |slice|
41
+ document_id = slice[0]
42
+ fields = slice.last unless no_content?
43
+ score = slice[1].to_f if with_scores?
44
+
45
+ Document.new(index, document_id, Hash[*fields.to_a], score)
46
+ end
47
+ end
44
48
  end
45
49
  end
46
50
  end
@@ -3,11 +3,19 @@
3
3
  module RediSearch
4
4
  class Search
5
5
  class Term
6
+ include ActiveModel::Validations
7
+
8
+ validates :fuzziness, numericality: {
9
+ only_integer: true, less_than: 4, greater_than: 0, allow_blank: true
10
+ }
11
+ validates :option, inclusion: { in: %i(fuzziness optional prefix) },
12
+ allow_nil: true
13
+
6
14
  def initialize(term, **options)
7
15
  @term = term
8
16
  @options = options
9
17
 
10
- validate_options
18
+ validate!
11
19
  end
12
20
 
13
21
  def to_s
@@ -23,7 +31,7 @@ module RediSearch
23
31
  attr_accessor :term, :options
24
32
 
25
33
  def fuzziness
26
- @fuzziness ||= options[:fuzziness].to_i
34
+ @fuzziness ||= options[:fuzziness]
27
35
  end
28
36
 
29
37
  def optional_operator
@@ -38,10 +46,14 @@ module RediSearch
38
46
  "*"
39
47
  end
40
48
 
49
+ def fuzzy_operator
50
+ "%" * fuzziness.to_i
51
+ end
52
+
41
53
  def stringify_query
42
54
  @term.to_s.
43
55
  tr("`", "\`").
44
- yield_self { |str| "#{'%' * fuzziness}#{str}#{'%' * fuzziness}" }.
56
+ yield_self { |str| "#{fuzzy_operator}#{str}#{fuzzy_operator}" }.
45
57
  yield_self { |str| "#{optional_operator}#{str}" }.
46
58
  yield_self { |str| "#{str}#{prefix_operator}" }.
47
59
  yield_self { |str| "`#{str}`" }
@@ -55,17 +67,8 @@ module RediSearch
55
67
  "[#{first} #{last}]"
56
68
  end
57
69
 
58
- def validate_options
59
- unsupported_options =
60
- (options.keys.map(&:to_s) - %w(fuzziness optional prefix)).join(", ")
61
-
62
- if unsupported_options.present?
63
- raise(ArgumentError,
64
- "#{unsupported_options} are unsupported term options")
65
- end
66
-
67
- raise(ArgumentError, "fuzziness can only be between 0 and 3") if
68
- fuzziness.negative? || fuzziness > 3
70
+ def option
71
+ options.keys.first&.to_sym
69
72
  end
70
73
  end
71
74
  end
@@ -37,11 +37,7 @@ module RediSearch
37
37
 
38
38
  def to_redis
39
39
  command.map do |arg|
40
- if !arg.to_s.starts_with?(/\(-?@/) && arg.to_s.split(/\s|\|/).size > 1
41
- arg.inspect
42
- else
43
- arg
44
- end
40
+ inspect_command_arg(arg)
45
41
  end.join(" ")
46
42
  end
47
43
 
@@ -63,5 +59,17 @@ module RediSearch
63
59
  def parse_response(response)
64
60
  @documents = Result.new(index, used_clauses, response[0], response[1..-1])
65
61
  end
62
+
63
+ def inspect_command_arg(arg)
64
+ if !arg.to_s.starts_with?(/\(-?@/) && arg.to_s.split(/\s|\|/).size > 1
65
+ arg.inspect
66
+ else
67
+ arg
68
+ end
69
+ end
70
+
71
+ def valid?
72
+ term_clause.present?
73
+ end
66
74
  end
67
75
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RediSearch
4
- VERSION = "1.0.0"
4
+ VERSION = "1.0.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redi_search
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Pezza
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-03 00:00:00.000000000 Z
11
+ date: 2019-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -145,9 +145,12 @@ files:
145
145
  - lib/redi_search/add.rb
146
146
  - lib/redi_search/alter.rb
147
147
  - lib/redi_search/client.rb
148
+ - lib/redi_search/client/response.rb
148
149
  - lib/redi_search/configuration.rb
149
150
  - lib/redi_search/create.rb
150
151
  - lib/redi_search/document.rb
152
+ - lib/redi_search/document/display.rb
153
+ - lib/redi_search/document/finder.rb
151
154
  - lib/redi_search/index.rb
152
155
  - lib/redi_search/lazily_load.rb
153
156
  - lib/redi_search/log_subscriber.rb