bibgrep 0.1.5

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