Class: GoldMine::IndexWriter

Inherits:
Object
  • Object
show all
Defined in:
lib/gold_mine/index_writer.rb

Overview

Creates a file which consists of a table describing the file, a table of pointers and an end of file position of related database. This file is called an index.

The index allows fast access to fortunes. Provides additional info about a database e.g gives information if fortunes are ordered or encrypted.

First argument is a path of fortune database. The second is an optional hash of options.

Options:

:index_path

The path under which the file will be saved.

:version

The version of writer.

:delim

The character which is used as delimiter in a database.

:randomized

Passing true will shuffle pointers.

:ordered

When enabled sorts pointers in an alphabetical order.

:rotated

Pass true if pointers should be encrypted (Caesar cipher).

:comments

If true allows comments in database.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, options = {}) ⇒ IndexWriter

Returns a new instance of IndexWriter.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/gold_mine/index_writer.rb', line 48

def initialize(path, options = {})
  @path = path

  options = self.class.default_options.merge(options)

  @options = options
  @longlen = 0
  @numstr = 0
  @eof = 0

  # It's very important to keep it high.
  # Otherwise in some cases shortest
  # string will not be assigned.
  #
  @shortlen = 99999

  @index_path = options[:index_path]
  @version = options[:version]
  @delim = options[:delim]

  # An arrangement excludes a randomness.
  #
  options[:randomized] = false if options[:ordered]

  @flags = BitSwitch.new({
    randomized: options[:randomized],
    ordered: options[:ordered],
    rotated: options[:rotated],
    comments: options[:comments]
  })

  @pointers = load_pointers
  @numstr = @pointers.size

  order_pointers! if @flags[:ordered]
  shuffle_pointers! if @flags[:randomized]
end

Instance Attribute Details

#delimObject (readonly)

Returns the value of attribute delim.



86
87
88
# File 'lib/gold_mine/index_writer.rb', line 86

def delim
  @delim
end

#flagsObject (readonly)

Returns the value of attribute flags.



86
87
88
# File 'lib/gold_mine/index_writer.rb', line 86

def flags
  @flags
end

#longlenObject (readonly)

Returns the value of attribute longlen.



86
87
88
# File 'lib/gold_mine/index_writer.rb', line 86

def longlen
  @longlen
end

#numstrObject (readonly)

Returns the value of attribute numstr.



86
87
88
# File 'lib/gold_mine/index_writer.rb', line 86

def numstr
  @numstr
end

#pointersObject (readonly)

Returns the value of attribute pointers.



86
87
88
# File 'lib/gold_mine/index_writer.rb', line 86

def pointers
  @pointers
end

#shortlenObject (readonly)

Returns the value of attribute shortlen.



86
87
88
# File 'lib/gold_mine/index_writer.rb', line 86

def shortlen
  @shortlen
end

#versionObject (readonly)

Returns the value of attribute version.



86
87
88
# File 'lib/gold_mine/index_writer.rb', line 86

def version
  @version
end

Class Method Details

.default_optionsObject



37
38
39
40
41
42
43
44
45
46
# File 'lib/gold_mine/index_writer.rb', line 37

def self.default_options
  @default_options ||= {
    version: 2,
    delim: "%",
    randomized: false,
    ordered: false,
    rotated: false,
    comments: false
  }
end

Instance Method Details

#index_pathObject

When a path for index is not defined returns identical path to the database, but adds .dat extension at the end.



93
94
95
# File 'lib/gold_mine/index_writer.rb', line 93

def index_path
  @index_path || "#{@path}.dat"
end

#load_pointersObject



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/gold_mine/index_writer.rb', line 97

def load_pointers
  dregex = /^#{@delim}/
  cregex = /^#{@delim*2}/
  fregex = /[a-zA-Z0-9]/
  pointers = []
  length = 0
  offset = 0
  fchar = ""
  new_string = true

  File.open(@path) do |file|
    file.each_with_index do |line, index|
      if @flags[:comments]
        next if line[cregex]
      end

      if new_string && !line[dregex]
        fchar = line[fregex][0] if line[fregex]
        offset = (file.pos - line.size)
        new_string = false
      end

      if line[dregex] || file.eof?
        if file.eof?
          @eof = file.pos
          length += line.size
        end

        unless length.zero?
          pointers << [offset, fchar]

          @longlen = length if length > @longlen
          @shortlen = length if length < @shortlen

          length = 0
          new_string = true
        end

        next
      end

      length += line.size
    end
  end

  pointers
end

#offsetsObject

Returns an array of pointers.

is an array. The array contains an offset at first and a first character of fortune as second. Described method extracts offsets.



164
165
166
# File 'lib/gold_mine/index_writer.rb', line 164

def offsets
  @pointers.map { |p| p.first }
end

#order_pointers!Object



145
146
147
# File 'lib/gold_mine/index_writer.rb', line 145

def order_pointers!
  @pointers.sort! { |x,y| [x[1], x[0]] <=> [y[1], y[0]] }
end

#packed_eofObject

Packs a database end of file position as 32-bit unsigned integer in big-endian byte order.



178
179
180
# File 'lib/gold_mine/index_writer.rb', line 178

def packed_eof
  [@eof].pack("N")
end

#packed_headerObject

Packs the header fields as 32-bit unsigned unsigned integers in big-endian byte order.



185
186
187
188
189
190
191
192
193
194
# File 'lib/gold_mine/index_writer.rb', line 185

def packed_header
  [
    @version,
    @numstr,
    @longlen,
    @shortlen,
    @flags.to_i,
    @delim.ord << 24 # bitpacked to 32-bit integer
  ].pack("N6")
end

#packed_pointersObject

Packs the pointers as 32-bit unsigned integers in big-endian byte order.



171
172
173
# File 'lib/gold_mine/index_writer.rb', line 171

def packed_pointers
  offsets.pack("N*")
end

#shuffle_pointers!Object



149
150
151
# File 'lib/gold_mine/index_writer.rb', line 149

def shuffle_pointers!
  @pointers = Hash[@pointers.to_a.shuffle]
end

#writeObject



153
154
155
# File 'lib/gold_mine/index_writer.rb', line 153

def write
  File.write(index_path, packed_header << packed_pointers << packed_eof)
end