This is an automated email from the ASF dual-hosted git repository.
sebb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/whimsy.git
The following commit(s) were added to refs/heads/master by this push:
new b7a1d921 Alternate parsing of members.txt
b7a1d921 is described below
commit b7a1d9216b3ddb81ac373a6820af62122133737a
Author: Sebb <[email protected]>
AuthorDate: Wed Mar 8 11:36:29 2023 +0000
Alternate parsing of members.txt
Returns all entries, even those without availids
---
lib/whimsy/asf/member.rb | 77 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/lib/whimsy/asf/member.rb b/lib/whimsy/asf/member.rb
index 1f714d5d..dd08bcba 100644
--- a/lib/whimsy/asf/member.rb
+++ b/lib/whimsy/asf/member.rb
@@ -1,4 +1,5 @@
require 'weakref'
+require 'wunderbar'
module ASF
class Member
@@ -132,6 +133,81 @@ module ASF
self.list.keys - self.status.keys
end
+ # convert key to symbol: replace non-alphanumeric with '_' and downcase
+ def self.key2sym(key)
+ Symbol === key ? key.downcase : key.gsub(%r{[^a-zA-Z0-9]},
'_').downcase.to_sym
+ end
+
+ # parse a single entry
+ # Params: keys_wanted array of key symbols to retrieve; defaults to
["Email"]
+ # Strings are forced to lower-case and non-alphanumeric replaced with '_'
+ def self.parse_entry(entry, keys_wanted=nil)
+ if keys_wanted.nil?
+ keys_wanted = %i{email}
+ end
+ # init array to collect matching key values, even if repeated
+ dict = {keys: keys_wanted.map{|k| [k,[]]}.to_h}
+ current_entry = nil
+ entry.each do |line|
+ if line =~ %r{^ +([^:]+): *(.*)}
+ val = $2.strip # must be done first otherwise $2 is clobbered
+ key = key2sym($1)
+ if keys_wanted.include? key
+ current_entry = dict[:keys][key]
+ current_entry << val
+ end
+ elsif current_entry and line.start_with? ' ' # needs to be indented
at least this much to be a continuation line
+ value = line.strip
+ current_entry << value if value.size > 0
+ else
+ current_entry = nil
+ end
+ end
+ dict
+ end
+
+ # return all user entries, whether or not they have an id
+ # Params: keys_wanted: array of key names to extract and return
+ # Returns: array of [status, user name, availid or nil, entry lines,
[keys]]
+ def self.list_entries(keys_wanted=nil)
+ # split by heading underlines; drop text before first
+ ASF::Member.text.split("\n").slice_before {|a| a.start_with?
'================'}.drop(1).each_with_index do |sect, index|
+ status = nil
+ # assume the sections remain in the original order
+ case index
+ when 0
+ status = :current
+ when 1
+ status = :emeritus
+ when 2
+ status = :other
+ when 3
+ status = :deceased
+ else
+ raise ArgumentError, "Unexpected section #{index} #{sect[1..2]}"
+ end
+ if status
+ sect.pop unless status == :deceased # drop next section name (except
at the end)
+ # extract the entries, dropping the leading text
+ sect.slice_before {|a| a.start_with? ' *)'}.drop(1).each do |entry|
+ # we always want the name
+ name = entry.first[4..-1].sub(%r{ +/\*.+}, '') # skip ' *) '; drop
comment
+ ids = []
+ entry.each {|e| ids << $1 if e =~ %r{^ +Avail ID: *(\S+)}}
+ if ids.length > 1
+ Wunderbar.error "Duplicate ids: #{ids} in #{name} entry"
+ end
+ if keys_wanted
+ yield status, name, ids.first, entry, self.parse_entry(entry,
keys_wanted.map!{|k| self.key2sym(k)})
+ else
+ yield status, name, ids.first, entry
+ end
+ end
+ end
+ end
+ nil
+ end
+
# An iterator that returns a list of ids and associated members.txt
entries.
def each
ASF::Member.text.to_s.split(/^ \*\) /).each do |section|
@@ -151,6 +227,7 @@ module ASF
# extract member emails from members.txt entry
def self.emails(text)
+ # RE looks for optional continuation lines starting with spaces followed
by nonspaces followed by '@'
text.to_s.scan(/Email: (.*(?:\n\s+\S+@.*)*)/).flatten.
join(' ').split(/\s+/).grep(/@/)
end