bomdb 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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