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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/bin/bibgrep +318 -0
  3. 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: []