bomdb 0.0.1 → 0.1.0

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
  SHA1:
3
- metadata.gz: 209c584dfb7167f1a15fb8c56c5f3875d5e38542
4
- data.tar.gz: 4916437d8203e3d2358936f747e4fe05b0a91b24
3
+ metadata.gz: e9e5b23505580c0871d836fffd14b2355a636562
4
+ data.tar.gz: 7c31fa7627d57d7f6a179d21ad8ccab40dcc108d
5
5
  SHA512:
6
- metadata.gz: fd1ddabc09baac5422810257ec93ed3133bbc90d6bc952602f97da6dcdb0f62f169423711d04ce39cb970cc88cf9358a6105f7d103c23c7f85ecd8673d9d6b15
7
- data.tar.gz: 38e2f20ece2af48daa61360b671f3b9d3a2b760b0757f20eb9bab6e22efa2a3185e3ba25aec4b02b9153abb08e6f19d0ee8cba785fa346ccd4c9218f3be0e838
6
+ metadata.gz: 69b236b5a23555654d6c2b311c7acd9f0c7767ff902957a50a0ed91db8c4c231b28e058e191f698ca840afbed8da02738cb3ffe9cc12d37cff009b71552f415b
7
+ data.tar.gz: f3bff6acf0729645bbd90677a229db21db19fe59ea2adec262bd086318b16adf3e917ce503244b6f0cf6effb95d9a6c8b1b6c45ab91c8b1b9355ffaac4483a1d
data/.gitignore CHANGED
@@ -1,13 +1,3 @@
1
1
  /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
- *.bundle
10
- *.so
11
- *.o
12
- *.a
13
- mkmf.log
2
+ /reference/
3
+ .DS_Store
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bomdb (0.0.1)
4
+ bomdb (0.1.0)
5
+ colorize (~> 0.7)
5
6
  constellation (~> 0.1)
6
7
  sequel (~> 4.21)
7
8
  sqlite3 (~> 1.3)
@@ -12,6 +13,7 @@ GEM
12
13
  specs:
13
14
  byebug (4.0.5)
14
15
  columnize (= 0.9.0)
16
+ colorize (0.7.5)
15
17
  columnize (0.9.0)
16
18
  constellation (0.1.1)
17
19
  multi_json
data/README.md CHANGED
@@ -4,6 +4,7 @@ This is a command-line tool (packaged as a Ruby gem) that provides multiple edit
4
4
 
5
5
  ## Usage
6
6
 
7
+ ### SHOW a formatted edition of the Book of Mormon
7
8
  Let's show the 1992 edition of the Book of Mormon:
8
9
 
9
10
  ```bash
@@ -26,7 +27,7 @@ Moroni 10:34 And now I bid unto all farewell. I soon go to rest in the paradise
26
27
  Suppose we want to remove the book, chapter, and verse headings from the output:
27
28
 
28
29
  ```bash
29
- $ bomdb show 1829 --no-book --no-chapter --no-verse
30
+ $ bomdb show 1829 --no-verse
30
31
 
31
32
  I Nephi having been born of goodly parents, therefore I was taught somewhat in all the learning of my father...
32
33
  # ... etc ...
@@ -40,6 +41,29 @@ $ bomdb show 1829 --exclude Bible-OT
40
41
  # ... shows 6080 verses instead of the usual 6604
41
42
  ```
42
43
 
44
+ ### ALIGN a new Book of Mormon text file
45
+
46
+ Suppose you have a new Book of Mormon text file that has been scanned from OCR or otherwise entered as a text file. It would take a lot of work to manually align all 6604 verses with the "standard" book, chapter, and verse numbers. Instead, BomDB helps automate this process:
47
+
48
+ Given this text:
49
+
50
+ ```
51
+ I, Nephi, having been born of goodly parents, therefore I was taught somewhat in all the learning of my father; and having seen many afflictions in the course of my days--nevertheless, having been highly favored of the Lord in all my days; yea, having had a great knowledge of the goodness and the mysteries of God, therefore I make a record of my proceedings in my days; yea, I make a record in the language of my father, which consists of the learning of the Jews and the language of the Egyptians. And I know that the record which I make is true; and I make it with mine own hand; and I make it according to my knowledge.
52
+ ```
53
+
54
+ You can automatically align and annotate it:
55
+
56
+ ```bash
57
+ $ bomdb align my_typed_bom.txt
58
+
59
+ # preamble text skipped...
60
+ 1 Nephi 1:2 yea, I make a record in the language of my father, which consists of the learning of the Jews and the language of the Egyptians.
61
+ 1 Nephi 1:3 And I know that the record which I make is true; and I make it with mine own hand; and I make it according to my knowledge.
62
+ # ... shows 6601 more verses
63
+ ```
64
+
65
+ Note that `align` requires the [dwdiff](http://linux.die.net/man/1/dwdiff) command on your system.
66
+
43
67
  ## Installation
44
68
 
45
69
  Add this line to your application's Gemfile:
data/bomdb.gemspec CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = "http://bomdb.wordtree.org"
14
14
  spec.license = "MIT"
15
15
 
16
- spec.files = `git ls-files -z`.split("\x0")
16
+ spec.files = `git ls-files -z`.split("\x0").reject{ |f| f =~ %r|data/.*\.json| }
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.add_dependency 'sqlite3', '~> 1.3'
24
24
  spec.add_dependency 'thor', '~> 0.19'
25
25
  spec.add_dependency 'constellation', '~> 0.1'
26
+ spec.add_dependency 'colorize', '~> 0.7'
26
27
 
27
28
  # spec.add_development_dependency 'bundler', '~> 1.7'
28
29
  spec.add_development_dependency 'rake', '~> 10.0'
Binary file
data/lib/bomdb.rb CHANGED
@@ -15,13 +15,27 @@ module BomDB
15
15
  end
16
16
  end
17
17
 
18
+ require 'byebug'
19
+
18
20
  require 'bomdb/version'
19
21
  require 'bomdb/config'
20
22
  require 'bomdb/schema'
21
23
  require 'bomdb/query'
22
24
 
25
+ require 'bomdb/diff/dwdiff'
26
+ require 'bomdb/diff/aligner'
27
+
23
28
  require 'bomdb/import/base'
24
29
  require 'bomdb/import/result'
25
30
  require 'bomdb/import/books'
26
31
  require 'bomdb/import/verses'
27
- require 'bomdb/import/biblical_refs'
32
+ require 'bomdb/import/editions'
33
+ require 'bomdb/import/contents'
34
+ require 'bomdb/import/refs'
35
+
36
+ require 'bomdb/export/base'
37
+ require 'bomdb/export/result'
38
+ require 'bomdb/export/books'
39
+ require 'bomdb/export/verses'
40
+ require 'bomdb/export/editions'
41
+ require 'bomdb/export/contents'
@@ -1,128 +1,274 @@
1
1
  require 'thor'
2
2
  require 'bomdb'
3
+ require 'colorize'
3
4
 
4
5
  module BomDB
5
6
  module Cli
6
7
  class Application < Thor
7
- desc "import TYPE", "import data of TYPE into database, e.g. books"
8
- option :reset, :type => :boolean, :default => false
9
- def import(type, file=nil)
10
- case type.downcase
11
- when 'books'
12
- result = import_books(file, options[:reset])
13
- show_result_and_maybe_exit(result)
14
- when 'verses'
15
- result = import_verses(file, options[:reset])
16
- show_result_and_maybe_exit(result)
17
- when 'biblical-refs'
18
- result = import_biblical_refs(true)
19
- show_result_and_maybe_exit(result)
8
+
9
+
10
+
11
+ desc "import FILE", "import data from FILE into database, e.g. books.json"
12
+ option :type, :type => :string, :default => nil
13
+ option :format, :type => :string, :default => 'json'
14
+ def import(file)
15
+ type = (options[:type] || type_from_file(file)).downcase
16
+ format = (options[:format] || format_from_file(file)).downcase
17
+
18
+ importer =
19
+ case type
20
+ when 'books' then BomDB::Import::Books.new(BomDB.db)
21
+ when 'verses' then BomDB::Import::Verses.new(BomDB.db)
22
+ when 'editions' then BomDB::Import::Editions.new(BomDB.db)
23
+ when 'contents' then BomDB::Import::Contents.new(BomDB.db)
24
+ when 'refs' then BomDB::Import::Refs.new(BomDB.db)
20
25
  else
21
26
  puts "Unknown import type #{type}"
22
27
  exit -1
23
28
  end
29
+
30
+ result = importer.import(read(file), format: format)
31
+ show_result_and_maybe_exit(result)
24
32
  end
25
33
 
26
- desc "build", "[delete and re-]build the database"
27
- option :delete, :type => :boolean, :default => false, :aliases => [:y]
28
- def build
29
- dbp = BomDB.config.db_path
30
- if File.exist?(dbp) and !options[:delete]
31
- puts "Database file '#{dbp}' exists. Delete? (y/N) "
34
+
35
+
36
+ desc "export TYPE", "export data from the database, e.g. books"
37
+ option :format, :type => :string, :default => 'json'
38
+ option :editions, :type => :string, :default => :all
39
+ def export(type)
40
+ format = options[:format].downcase
41
+
42
+ exporter =
43
+ case type
44
+ when 'books' then BomDB::Export::Books.new(BomDB.db)
45
+ when 'verses' then BomDB::Export::Verses.new(BomDB.db)
46
+ when 'editions' then BomDB::Export::Editions.new(BomDB.db)
47
+ when 'contents' then BomDB::Export::Contents.new(BomDB.db, edition_prefixes: options[:editions])
48
+ # when 'refs' then BomDB::Export::Refs.new(BomDB.db)
49
+ else
50
+ puts "Unknown import type #{type}"
51
+ exit -1
52
+ end
53
+
54
+ result = exporter.export(format: format)
55
+ if result.success?
56
+ puts result.to_s
57
+ else
58
+ show_result_and_maybe_exit(result)
59
+ end
60
+ end
61
+
62
+
63
+
64
+ desc "create", "create a new Book of Mormon database"
65
+ option :file, :type => :string, :default => BomDB.config.db_path,
66
+ :description => "the filepath of the database file on disk"
67
+ option :bare, :type => :boolean, :default => false,
68
+ :description => "create a bare database without any data"
69
+ option :delete, :type => :boolean, :default => false, :aliases => [:y],
70
+ :description => "don't ask for confirmation before overwriting an existing database"
71
+ def create
72
+ db_path = options[:file]
73
+
74
+ if File.exist?(db_path) and !options[:delete]
75
+ puts "Database file '#{db_path}' exists. Delete? (y/N) "
32
76
  if $stdin.gets.chomp.downcase != "y"
33
77
  puts "Exiting..."
34
78
  exit -1
35
79
  end
80
+ verbing = 'Overwriting'
81
+ else
82
+ verbing = 'Creating'
36
83
  end
37
84
 
38
- # Delete the database
39
- FileUtils.rm(dbp)
85
+ puts "#{verbing} database '#{db_path}' ..."
86
+ schema = BomDB::Schema.create(db_path)
87
+ puts "Created the following tables:"
88
+ schema.db.tables.each{ |t| puts "\t#{t}" }
40
89
 
41
- puts "Importing books..."
42
- show_result_and_maybe_exit(import_books(nil, true))
90
+ unless options[:bare]
91
+ puts "Importing books..."
92
+ import('books.json')
43
93
 
44
- puts "Importing verses..."
45
- show_result_and_maybe_exit(import_verses(nil, true))
94
+ puts "Importing verses..."
95
+ import('verses.json')
46
96
 
47
- puts "Importing biblical refs..."
48
- show_result_and_maybe_exit(import_biblical_refs(true))
97
+ puts "Importing editions..."
98
+ import('editions.json')
49
99
 
100
+ puts "Importing contents..."
101
+ import('contents.json')
102
+
103
+ puts "Importing refs..."
104
+ import('refs.json')
105
+ end
106
+
107
+ puts "Done."
50
108
  end
51
109
 
110
+
111
+
52
112
  desc "show EDITION RANGE", "show an edition of the Book of Mormon, or a RANGE of verses"
53
- option :book, :type => :boolean, :default => true, :aliases => [:b]
54
- option :chapter, :type => :boolean, :default => true, :aliases => [:c]
55
- option :verse, :type => :boolean, :default => true, :aliases => [:v]
56
- option :exclude, :type => :string, :aliases => [:x]
57
- option :sep, :type => :string, :default => ' '
113
+ option :verse, :type => :boolean, :default => true,
114
+ :description => "show book, chapter, verse annotations"
115
+ option :exclude, :type => :string, :aliases => [:x],
116
+ :description => "exclude verses that are references, e.g. Bible-OT references"
117
+ option :sep, :type => :string, :default => " ",
118
+ :description => "separator between annotations and content, defaults to ' '"
119
+ option :linesep, :type => :string, :default => "\n",
120
+ :description => "separator between verses. Defaults to newline ('\\n')."
121
+ option :color, :type => :boolean, :default => true,
122
+ :description => "show chapter and verse in color"
123
+ option :"for-alignment", :type => :boolean, :default => false,
124
+ :description => "show output in 'alignment' mode. Useful for debugging 'align' subcommand issues."
58
125
  def show(edition = '1829', range = nil)
59
- query = BomDB::Query.new(
126
+ body_format = nil
127
+ if options[:"for-alignment"]
128
+ linesep = " "
129
+ verse_format = verse_format_for_alignment(options[:color])
130
+ else
131
+ linesep = options[:linesep]
132
+ if options[:verse]
133
+ if options[:color]
134
+ verse_format = lambda{ |b,c,v| b.colorize(:yellow) + ' ' +
135
+ c.to_s.colorize(:green) + ':' +
136
+ v.to_s.colorize(:light_green) }
137
+ else
138
+ verse_format = nil
139
+ end
140
+ else
141
+ verse_format = lambda{ |b,c,v| '' }
142
+ end
143
+ end
144
+ BomDB::Query.new(
60
145
  edition: edition,
61
146
  exclude: options[:exclude]
62
147
  # range: range
63
- )
64
- query.print(
65
- book: options[:book],
66
- chapter: options[:chapter],
67
- verse: options[:verse],
68
- sep: options[:sep]
148
+ ).print(
149
+ verse_format: verse_format,
150
+ body_format: body_format,
151
+ sep: options[:sep],
152
+ linesep: linesep
69
153
  )
70
154
  end
71
155
 
156
+
157
+
72
158
  desc "editions", "list available editions of the Book of Mormon"
73
- # option :available, :type => :boolean, :default => true
159
+ option :all, :type => :boolean, :default => false
74
160
  def editions
75
- eds = BomDB.db[:versions].map do |r|
76
- [r[:version_year], r[:version_name]].join(' -- ')
77
- end
78
- puts eds.join('\n')
161
+ eds = BomDB.db[:editions].
162
+ left_outer_join(:contents, :edition_id => :edition_id).
163
+ select_group(:edition_name).
164
+ select_append{ Sequel.as(count(:verse_id), :count) }.
165
+ order(:edition_name).
166
+ map { |r| "#{r[:count]} verses\t#{r[:edition_name]}" }
167
+ puts eds.join("\n")
79
168
  end
80
169
 
81
- desc "reference-types", "list reference types"
82
- def reference_types
83
- rts = BomDB.db[:refs].distinct.select(:ref_name).map do |r|
84
- r[:ref_name]
170
+
171
+
172
+ desc "references TYPE", "list reference types or references of TYPE"
173
+ def references(type=nil)
174
+ if type.nil?
175
+ rts = BomDB.db[:refs].
176
+ select_group(:ref_name).
177
+ select_append{ Sequel.as(count(ref_id), :count) }.
178
+ map { |r| "#{r[:ref_name]} (#{r[:count]} refs)" }
179
+ puts rts.join("\n")
180
+ else
181
+ rts = BomDB.db[:refs].where(:ref_name => type).
182
+ map{ |r| "#{r[:ref_book]} #{r[:ref_chapter]}:#{r[:ref_verse]}" }
183
+ puts rts.join("\n")
85
184
  end
86
- puts rts.join('\n')
87
185
  end
88
186
 
89
- private
90
187
 
91
- def datafile(file)
92
- File.join(BomDB.config.data_dir, file)
188
+
189
+ desc "align FILE EDITION", "give verse annotations from EDITION to a new Book of Mormon text FILE that lacks verse annotations"
190
+ option :dwdiff, :type => :string, :default => "/usr/local/bin/dwdiff",
191
+ :description => "the filepath of the dwdiff binary (shell command)"
192
+ option :'edition-only', :type => :boolean, :default => false,
193
+ :description => "show the alignment-formatted edition output only (useful for debugging)"
194
+ option :'diff-only', :type => :boolean, :default => false,
195
+ :description => "show the dwdiff output only (useful for debugging)"
196
+ def align(file, edition = '1829')
197
+ io = StringIO.new
198
+
199
+ BomDB::Query.new(edition: edition).print(
200
+ verse_format: verse_format_for_alignment,
201
+ linesep: ' ',
202
+ io: io
203
+ )
204
+ if options[:'edition-only']
205
+ puts io.string
206
+ exit
207
+ end
208
+
209
+ dwdiff = Diff::Dwdiff.new(options[:dwdiff])
210
+ diff = dwdiff.diff(io.string, File.read(file))
211
+
212
+ if options[:'diff-only']
213
+ puts diff
214
+ exit
215
+ end
216
+
217
+ puts Diff::Aligner.parse(diff)
93
218
  end
94
219
 
95
- def import_books(file, reset = true)
96
- data = File.read(file || datafile("books.json"))
97
220
 
98
- import = BomDB::Import::Books.new(BomDB.db)
99
- import.reset if reset
100
221
 
101
- import.json(data)
222
+ private
223
+
224
+ def datafile(file)
225
+
102
226
  end
103
227
 
104
- def import_verses(file, reset = true)
105
- data = File.read(file || datafile("verses.json"))
228
+ def read(file)
229
+ File.read(relative_or_data_file(file))
230
+ end
106
231
 
107
- import = BomDB::Import::Verses.new(BomDB.db)
108
- import.reset if reset
232
+ def relative_or_data_file(file)
233
+ if File.exist?(file)
234
+ file
235
+ else
236
+ if File.basename(file) == file
237
+ # Try our gem's data directory as a fallback for this file
238
+ File.join(BomDB.config.data_dir, file)
239
+ else
240
+ $stderr.puts "File not found: #{file}"
241
+ exit -1
242
+ end
243
+ end
244
+ end
109
245
 
110
- import.json(data)
246
+ def format_from_file(file)
247
+ case File.extname(file).downcase
248
+ when ".txt" then "text"
249
+ when ".json" then "json"
250
+ else
251
+ $stderr.puts "Unable to determine format from file: #{file}"
252
+ exit -1
253
+ end
111
254
  end
112
255
 
113
- def import_biblical_refs(reset = true)
114
- import = BomDB::Import::BiblicalRefs.new(BomDB.db)
115
- import.reset if reset
256
+ def type_from_file(file)
257
+ type = File.basename(file).gsub(/\.(txt|json)$/, '').downcase
258
+ end
116
259
 
117
- import.import
260
+ def verse_format_for_alignment
261
+ verse_format = lambda do |book, chapter, verse|
262
+ "[|#{book} #{chapter}:#{verse}|]"
263
+ end
118
264
  end
119
265
 
120
266
  def show_result_and_maybe_exit(result)
121
- if !result.success?
122
- puts result.message
123
- # if result.error.is_a?(Sequel::UniqueConstraintViolation)
124
- puts "Try again with '--reset'? (NOTE: data may be deleted)"
125
- # end
267
+ if result.success?
268
+ $stderr.puts "Success"
269
+ else
270
+ $stderr.puts result.message
271
+ # $stderr.puts "Try again with '--reset'? (NOTE: data may be deleted)"
126
272
  exit -1
127
273
  end
128
274
  end