bibgrep 0.1.5
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 +7 -0
- data/bin/bibgrep +318 -0
- metadata +58 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 452a22378708e35559fda8ccbcb625b2c7f45a7e
|
4
|
+
data.tar.gz: bd4b015a50b3ff47bf612610e1a67a32930e3f6b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 93eba2c010f83f39d090fd354edc414c80c90218f65cafd49b79643abbd5dacdcabe705a23824ef25552b8eeb67d942025efd2cbc43b45655a6c90be95817886
|
7
|
+
data.tar.gz: 6b40f8c2bb1a00b0a64ebae81099ca2e4930c127383ef0868cc2d7c2de0c524702d13465c2754b978569c53d040dca5134fdd6b1770191e7ccadd390d7fac0e9
|
data/bin/bibgrep
ADDED
@@ -0,0 +1,318 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Version
|
4
|
+
VERSION = '0.1.5 (23-04-13)'
|
5
|
+
|
6
|
+
# If no regex is given,. check the field exists
|
7
|
+
DEFAULT_RX = "\.+"
|
8
|
+
|
9
|
+
# These are not technically internal keys, but metadata which
|
10
|
+
# should still be searchable. The is a limitation of the library.
|
11
|
+
PSEUDO_KEYS = %w{key type}
|
12
|
+
|
13
|
+
# Field separator for non-bibtex-format output
|
14
|
+
DEFAULT_SEPARATOR = ": "
|
15
|
+
|
16
|
+
OPTIONS = {
|
17
|
+
:f => {:desc => "Output filename (default if multiple files used)"},
|
18
|
+
:F => {:desc => "Suppress filename output with multiple files."},
|
19
|
+
:p => {:desc => "Suppress placeholders for empty fields"},
|
20
|
+
|
21
|
+
# Raw output
|
22
|
+
:r => {:desc => "Output BibTeX (Cannot be used with -o)"},
|
23
|
+
:o => {:desc => "Specify output fields (o[=]field[,field[,field]])"},
|
24
|
+
:s => {:desc => "Specify field separator (s[=]sepstring). Default is '#{DEFAULT_SEPARATOR}'."},
|
25
|
+
|
26
|
+
# Regex options
|
27
|
+
:v => {:desc => "Invert match"},
|
28
|
+
:i => {:desc => "Case-insensitive regex"},
|
29
|
+
:e => {:desc => "Extended regex"},
|
30
|
+
:m => {:desc => "Multi-line regex"},
|
31
|
+
|
32
|
+
# BibTeX options
|
33
|
+
:c => {:desc => "Process comment types"},
|
34
|
+
:w => {:desc => "Suppress BibTeX validity warnings"},
|
35
|
+
|
36
|
+
# Misc.
|
37
|
+
# :q => {:desc => "Suppress file warnings"},
|
38
|
+
:V => {:desc => "Verbose (list conditions)"},
|
39
|
+
:h => {:desc => "Output help"}
|
40
|
+
}
|
41
|
+
|
42
|
+
|
43
|
+
# Default options to use when none are specified
|
44
|
+
DEFAULT_OPTIONS = "rw".chars.map{|c| c.to_sym}
|
45
|
+
|
46
|
+
# Print usage, version info
|
47
|
+
def usage
|
48
|
+
$stderr.puts "BibGrep v#{VERSION}"
|
49
|
+
$stderr.puts ""
|
50
|
+
$stderr.puts "USAGE: #{File.basename($0)} [-FLAGS] [-oFIELD] [-o=FIELD[,FIELD2[,...]]] [+FIELD[=RX] [+FIELD[=RX] [...]]] [FILE [FILE [...]]"
|
51
|
+
$stderr.puts ""
|
52
|
+
$stderr.puts "Where..."
|
53
|
+
$stderr.puts " FIELD : A BibTeX key to match on."
|
54
|
+
$stderr.puts " RX : Regex to match against the field. Omitting"
|
55
|
+
$stderr.puts " a pattern means we use the default, /#{DEFAULT_RX}/"
|
56
|
+
$stderr.puts " FILE : The BibTeX file(s) to parse. If your filename"
|
57
|
+
$stderr.puts " begins with a dash, prefix the argument with "
|
58
|
+
$stderr.puts " two dashes thus: 'lsbib -- -.bib'"
|
59
|
+
|
60
|
+
$stderr.puts " FIELD : One of BibTeX's field names or one of #{PSEUDO_KEYS.map{|x| "'#{x}'"}.join(", ")}."
|
61
|
+
$stderr.puts " Not case-sensitive."
|
62
|
+
$stderr.puts " FLAGS : A string containing some of the options below."
|
63
|
+
$stderr.puts " Default is -#{DEFAULT_OPTIONS.join('')}."
|
64
|
+
OPTIONS.each{|k,v|
|
65
|
+
$stderr.puts " -#{k} : #{v[:desc]}"
|
66
|
+
}
|
67
|
+
$stderr.puts ""
|
68
|
+
$stderr.puts "NB: If no files are given, I will read from stdin."
|
69
|
+
end
|
70
|
+
|
71
|
+
# Parse input options, returning:
|
72
|
+
# input files and filenames
|
73
|
+
# a hash of conditions to apply to bibtex
|
74
|
+
# option flags
|
75
|
+
def parse_args
|
76
|
+
# Create slots for conditions and files
|
77
|
+
files = {}
|
78
|
+
conditions = {}
|
79
|
+
options = DEFAULT_OPTIONS
|
80
|
+
output = []
|
81
|
+
separator = DEFAULT_SEPARATOR
|
82
|
+
|
83
|
+
# Parse input arguments
|
84
|
+
force_file = false
|
85
|
+
default_options = true
|
86
|
+
ARGV.each{|a|
|
87
|
+
|
88
|
+
# Test if it's an argument or a file
|
89
|
+
if %w{- +}.include?(a[0]) and not force_file then
|
90
|
+
|
91
|
+
|
92
|
+
# Check for separator
|
93
|
+
if a == '--' then
|
94
|
+
# Separator, turn force file mode on
|
95
|
+
force_file = true
|
96
|
+
elsif a[0] == '+' then
|
97
|
+
# condition
|
98
|
+
a = a[1..-1] # Remove prefixed dash
|
99
|
+
value = DEFAULT_RX
|
100
|
+
key = a
|
101
|
+
if equals = a.index('=') then
|
102
|
+
key = a[0..(equals-1)]
|
103
|
+
value = a[(equals+1)..-1]
|
104
|
+
end
|
105
|
+
|
106
|
+
# Assign to list of things to check
|
107
|
+
conditions[key] = value
|
108
|
+
elsif a[0] == '-' then
|
109
|
+
if default_options
|
110
|
+
options = []
|
111
|
+
default_options = false
|
112
|
+
end
|
113
|
+
|
114
|
+
# option
|
115
|
+
long_arg = false
|
116
|
+
(1..(a.length-1)).each{|i|
|
117
|
+
if not long_arg then
|
118
|
+
# Single-char options
|
119
|
+
o = a[i]
|
120
|
+
|
121
|
+
if OPTIONS.keys.include?(o.to_sym)
|
122
|
+
|
123
|
+
# Handle output specially
|
124
|
+
if o == 'o' then
|
125
|
+
options << :o
|
126
|
+
# Tell the loop to ignore further things from this group
|
127
|
+
long_arg = true
|
128
|
+
|
129
|
+
# Ignore leading equals and cut up by space
|
130
|
+
fields = a[(i+1)..-1].gsub(/^=/, '').split(',')
|
131
|
+
if fields.length > 0 then
|
132
|
+
output += fields
|
133
|
+
end
|
134
|
+
|
135
|
+
elsif o == 's' then
|
136
|
+
options << :s
|
137
|
+
|
138
|
+
# Tell the loop to ignore further things from this group
|
139
|
+
long_arg = true
|
140
|
+
|
141
|
+
# Ignore leading equals and cut up by space
|
142
|
+
separator = a[(i+1)..-1].gsub(/^=/, '').to_s
|
143
|
+
else
|
144
|
+
# Flag option
|
145
|
+
options << o.to_sym
|
146
|
+
end
|
147
|
+
else
|
148
|
+
$stderr.puts "Unrecognised option: #{o}"
|
149
|
+
# force help
|
150
|
+
options << :h
|
151
|
+
end
|
152
|
+
end
|
153
|
+
}
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
else
|
158
|
+
# file
|
159
|
+
if not File.readable?(a) then
|
160
|
+
$stderr.puts "Cannot read #{a}"
|
161
|
+
elsif File.directory?(a) then
|
162
|
+
$stderr.puts "#{a} is a directory"
|
163
|
+
else
|
164
|
+
files[a] = File.open(a)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
}
|
168
|
+
|
169
|
+
# Check that either -r or -o=field is given
|
170
|
+
if options.include?(:r) and output.length > 0 then
|
171
|
+
$stderr.puts "Option -r cannot be used with -o."
|
172
|
+
options << :h
|
173
|
+
end
|
174
|
+
|
175
|
+
# Default to stdin
|
176
|
+
files['<stdin>'] = STDIN if files.length == 0
|
177
|
+
|
178
|
+
# List filename by default if file length over 1
|
179
|
+
options << :f if not options.include?(:n) and files.length > 1
|
180
|
+
options.delete(:f) if options.include?(:F)
|
181
|
+
|
182
|
+
# Construct regex according to options
|
183
|
+
rx_flags = 0
|
184
|
+
rx_flags |= Regexp::IGNORECASE if options.include?(:i)
|
185
|
+
rx_flags |= Regexp::EXTENDED if options.include?(:e)
|
186
|
+
rx_flags |= Regexp::MULTILINE if options.include?(:m)
|
187
|
+
conditions.each{ |k, v|
|
188
|
+
conditions[k] = Regexp.new(v, rx_flags)
|
189
|
+
}
|
190
|
+
|
191
|
+
return files, conditions, options.uniq, output, separator
|
192
|
+
end
|
193
|
+
|
194
|
+
# -----------------------------------------------------------------------------
|
195
|
+
# Entry point
|
196
|
+
# -----------------------------------------------------------------------------
|
197
|
+
# Check the prerequisites match
|
198
|
+
begin
|
199
|
+
gem 'bibtex-ruby'
|
200
|
+
rescue
|
201
|
+
$stderr.puts "Please install the `bibtex-ruby' gem."
|
202
|
+
exit(1)
|
203
|
+
end
|
204
|
+
require 'bibtex'
|
205
|
+
|
206
|
+
|
207
|
+
|
208
|
+
# -----------------------------------------------------------------------------
|
209
|
+
# Load everything from ARGV
|
210
|
+
files, conditions, options, fields, separator = parse_args
|
211
|
+
|
212
|
+
|
213
|
+
|
214
|
+
|
215
|
+
# -----------------------------------------------------------------------------
|
216
|
+
# If the help flag is set simply output help then exit
|
217
|
+
if options.include?(:h) then
|
218
|
+
usage
|
219
|
+
exit(1)
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
|
224
|
+
# -----------------------------------------------------------------------------
|
225
|
+
# Summarise, if requested
|
226
|
+
if options.include?(:V) then
|
227
|
+
puts "Input files:"
|
228
|
+
files.keys.each{|f|
|
229
|
+
puts " #{f}"
|
230
|
+
}
|
231
|
+
|
232
|
+
puts "\nFilters:"
|
233
|
+
conditions.each{|k, v|
|
234
|
+
puts " #{k}: #{v.inspect}"
|
235
|
+
}
|
236
|
+
|
237
|
+
puts "\nOutput fields:"
|
238
|
+
fields.each{|f|
|
239
|
+
puts " #{f}"
|
240
|
+
}
|
241
|
+
|
242
|
+
puts "\nActive Options: "
|
243
|
+
options.each{|o|
|
244
|
+
puts " #{o}: #{OPTIONS[o][:desc]}"
|
245
|
+
}
|
246
|
+
puts ""
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
|
251
|
+
|
252
|
+
# -----------------------------------------------------------------------------
|
253
|
+
# Processing loop proper.
|
254
|
+
files.each{|filename, f|
|
255
|
+
# Check validity, but don't let it stop us parsing.
|
256
|
+
$stderr.puts "BibTeX file #{filename} is invalid" if not options.include?(:w) and not BibTeX.valid?(f)
|
257
|
+
|
258
|
+
# Open file, optimistically
|
259
|
+
bib = BibTeX.parse(f.read)
|
260
|
+
bib.each{|b|
|
261
|
+
if options.include?(:c) or b.type.to_s.downcase != 'comment' then
|
262
|
+
# Perform matching by unmatching things
|
263
|
+
# this does an AND in the arguments list
|
264
|
+
match = true
|
265
|
+
conditions.each{|key, rx|
|
266
|
+
|
267
|
+
# Check matching on the condition, with the key or pseudo-key (object property)
|
268
|
+
if not ((PSEUDO_KEYS.include?(key)) ? b.send(key.to_sym) : b[key]) =~ rx
|
269
|
+
# cancel the match
|
270
|
+
match = false
|
271
|
+
else
|
272
|
+
# Report verbose matching info
|
273
|
+
puts "Entry #{b.key} in file #{filename} matches on key #{key}" if options.include?(:V)
|
274
|
+
end
|
275
|
+
}
|
276
|
+
|
277
|
+
# Invert match if requested
|
278
|
+
match = (not match) if options.include?(:v)
|
279
|
+
|
280
|
+
# output
|
281
|
+
if match then
|
282
|
+
|
283
|
+
# define output
|
284
|
+
output = []
|
285
|
+
|
286
|
+
# check if we want raw output or not
|
287
|
+
if options.include?(:r) then
|
288
|
+
output << b.to_s
|
289
|
+
else
|
290
|
+
# Add the filename if people want
|
291
|
+
output << "#{filename}" if options.include?(:f)
|
292
|
+
|
293
|
+
# Then check each option to retain order
|
294
|
+
# Fields are not available for comments, so simply output the contents if -c is set:
|
295
|
+
if options.include?(:c) and b.type.to_s.downcase == 'comment' then
|
296
|
+
output << b.content
|
297
|
+
else
|
298
|
+
fields.each{|f|
|
299
|
+
# Load value and apply placeholder if empty
|
300
|
+
val = nil
|
301
|
+
begin
|
302
|
+
val = b.send(f.to_sym)
|
303
|
+
rescue Exception
|
304
|
+
end
|
305
|
+
val ||= "<no #{f}>" if not options.include?(:p)
|
306
|
+
|
307
|
+
# Add to the output array
|
308
|
+
output << val.to_s
|
309
|
+
}
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# and output
|
314
|
+
puts output.join(separator.to_s) if output.length > 0
|
315
|
+
end
|
316
|
+
end
|
317
|
+
}
|
318
|
+
}
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bibgrep
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stephen Wattam
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-04-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bibtex-ruby
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.3'
|
27
|
+
description: A tool for searching and organising bibtex
|
28
|
+
email: stephenwattam@gmail.com
|
29
|
+
executables:
|
30
|
+
- bibgrep
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- bin/bibgrep
|
35
|
+
homepage: http://stephenwattam.com/projects/bibgrep
|
36
|
+
licenses: []
|
37
|
+
metadata: {}
|
38
|
+
post_install_message: Have fun.
|
39
|
+
rdoc_options: []
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.9'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 2.0.0
|
55
|
+
signing_key:
|
56
|
+
specification_version: 4
|
57
|
+
summary: grep for Bibtex
|
58
|
+
test_files: []
|