contacts_txt 0.2.11 → 0.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 355e8353cd10e38ee6e8bc865b994089e69543c4a3b5e7e78de1fdc76b363eaf
4
- data.tar.gz: 7a9e5e5df3864776b0e11574f50b26ff23243ac32d4d36fe729358841b5c5a91
3
+ metadata.gz: bf478e02d22813b059b002369a94120ffa7db0c98e7ee02f7eb5a7604f000e36
4
+ data.tar.gz: 0e220217e01429b1b35c059df1e8459100ee4003a618c8634dcafd09ca30baeb
5
5
  SHA512:
6
- metadata.gz: 51bf53d2aa3526fa69537e79444d80a05a8d958bed6f919b7268374b17b8df5c544bee3c3573b112d710114f0fe7130d0e62dcd36f35bdf9cf6912cd16bfec0e
7
- data.tar.gz: fc269d1fee4f6e48ca53f5917f4ea48c9681ba998eb96724b23cf069b6a15a548f1dfeb428071a66c97d36a1fd6e59381ab36e126ef1bde29ab78dbb8a0f40a1
6
+ metadata.gz: 71e031cd9bef37e5d93c634832d2ba450a17605cbbf5c088898a73b1678cb0c477bfce0eddfa60604c784805b3126bd8e1305ebc494e78927aea4024339e0752
7
+ data.tar.gz: 1d0686e575cd7242676541d2ad093a113c5ffd95666f56450d1139376d4d399ecd6c67e7b547f9118e02cc4f7e42620e93dd2752b550f445c43cab008d216a0c
checksums.yaml.gz.sig CHANGED
Binary file
data/lib/contacts_txt.rb CHANGED
@@ -3,26 +3,27 @@
3
3
  # file: contacts_txt.rb
4
4
 
5
5
  require 'dynarex'
6
+ require 'rxfreadwrite'
6
7
 
7
8
 
8
9
  class ContactsTxt
9
- include RXFHelperModule
10
+ include RXFReadWriteModule
10
11
 
11
12
  attr_reader :to_s
12
-
13
- def initialize(src=nil, fields: %w(role organisation mobile
14
- sms email dob tags address notes note mobile2 ),
13
+
14
+ def initialize(src=nil, fields: %w(role organisation mobile
15
+ sms email dob tags address notes note mobile2 ),
15
16
  username: nil, password: nil, debug: false)
16
-
17
+
17
18
  @debug = debug
18
19
  @fields = %w(fullname firstname lastname tel) | fields
19
20
 
20
21
  txt, type = if src then
21
- RXFHelper.read(src, username: username, password: password)
22
+ RXFReader.read(src, username: username, password: password)
22
23
  else
23
24
  ['', :unknown]
24
25
  end
25
-
26
+
26
27
  case type
27
28
  when :file
28
29
  @path, @filename = File.dirname(src), File.basename(src)
@@ -33,94 +34,165 @@ class ContactsTxt
33
34
  when :unknown
34
35
  @path, @filename = '.', 'contacts.txt'
35
36
  end
36
-
37
+
37
38
  @dx = txt.lines.length > 1 ? import_to_dx(txt) : new_dx()
38
39
 
39
40
  end
40
-
41
+
42
+ def all()
43
+ @dx.all
44
+ end
45
+
41
46
  def dx()
42
47
  @dx
43
48
  end
44
-
49
+
45
50
  def find_by_id(id)
46
-
51
+
47
52
  @dx.find_by_id id
48
-
53
+
49
54
  end
50
-
55
+
51
56
  def find_by_mobile(raw_number, countrycode='44')
52
57
 
53
58
  number = Regexp.new raw_number.sub(/^(?:0|#{countrycode})/,'').gsub(/[ -]*/,'')
54
-
55
- @dx.all.find {|x| x.mobile.gsub(/[ -]*/,'') =~ number }
56
59
 
57
- end
58
-
59
- def find_by_name(raw_name)
60
+ @dx.all.find {|x| x.mobile.gsub(/[ -]*/,'') =~ number }
61
+
62
+ end
63
+
64
+ def find_by_name(s)
65
+
66
+ # Appending a hashtag to the name can help with finding the specific record
67
+ # e.g. 'Peter#plumber' or 'Peter #plumber'
68
+
69
+ raw_name, tag = s.split('#',2).map(&:strip)
60
70
 
61
71
  name = Regexp.new "\b#{raw_name}\b|#{raw_name}", Regexp::IGNORECASE
62
72
  puts 'name: ' + name.inspect if @debug
63
-
64
- @dx.all.select do |x|
73
+
74
+ a = @dx.all.select do |x|
65
75
  x.fullname =~ name or x.firstname =~ name or x.lastname =~ name
66
76
  end
67
77
 
68
- end
69
-
78
+ if tag then
79
+ a.find {|x| x.tags.split.map(&:downcase).include? tag.downcase }
80
+ else
81
+ a
82
+ end
83
+
84
+ end
85
+
70
86
  def find_by_sms(raw_number, countrycode='44')
71
87
 
72
88
  number = Regexp.new raw_number\
73
89
  .sub(/^(?:0|#{countrycode})/,'').gsub(/[ -]*/,'')
74
-
90
+
75
91
  @dx.all.find {|x| x.sms.gsub(/[ -]*/,'') =~ number \
76
- or x.mobile.gsub(/[ -]*/,'') =~ number }
92
+ or x.mobile.gsub(/[ -]*/,'') =~ number }
77
93
 
78
- end
79
-
80
- # find using the tel, mobile, or mobile2 fields
94
+ end
95
+
96
+ # find using the tel, mobile, or mobile2 fields
81
97
  #
82
98
  def find_by_telno(raw_number)
83
99
 
84
100
  number = Regexp.new raw_number.gsub(/[ -]*/,'')
85
-
101
+
86
102
  @dx.all.find do |x|
87
-
103
+
88
104
  numbers = %i(tel mobile mobile2).map do |y|
89
105
  x.method(y).call.gsub(/[ -]*/,'') if x.respond_to? y
90
106
  end
91
-
107
+
92
108
  puts 'numbers: ' + numbers.inspect if @debug
93
109
  numbers.grep(number).any?
94
110
  end
95
111
 
96
- end
112
+ end
97
113
 
98
114
  # returns a Dynarex object
99
- #
115
+ #
100
116
  def email_list()
101
117
  @dx.filter {|x| x.email.length > 0}
102
118
  end
103
-
119
+
104
120
  def list_names()
105
-
121
+
106
122
  @dx.all.inject([]) do |r, x|
107
123
  x.fullname.length >= 1 ? r << x.fullname : r
108
124
  end
109
125
 
110
126
  end
111
-
127
+
112
128
  def mobile_list()
113
129
  @dx.filter {|x| x.mobile.length > 0}
114
- end
130
+ end
131
+
132
+ def multi_tel_index()
133
+
134
+ a = @dx.all.map do |x|
135
+
136
+ tel = %i(tel mobile mobile2).detect do |name|
137
+ !x.method(name).call.empty?
138
+ end
139
+ next unless tel
140
+ "%s %s" % [x.fullname, x.method(tel).call]
141
+ end.compact
142
+
143
+
144
+ # group by first name
145
+ r = a.group_by {|x| x[0]}
146
+
147
+ a2 = a.clone
148
+
149
+ # group by last name
150
+ r2 = a.group_by {|x| x.split(/ /,2).last[0]}
151
+ c = r2.merge(r)
152
+
153
+ c.each do |k, v|
154
+
155
+ puts "k: %s v: %s" % [k, v]
156
+ v.concat(r2[k]) if r2[k]
157
+
158
+ end
159
+
160
+ h = c.sort.each {|k,v| v.uniq!}.to_h
161
+
162
+ out = []
163
+
164
+ h.each do |k,v|
165
+
166
+ out << ' ' + (' ' * 30) + k
167
+
168
+ v.each do |x|
169
+
170
+ name, phone = x.split(/(?=\d)/,2)
171
+ out << "\n" + (name.length >= 29 ? name[0..26] + '...' : name)
172
+ tel = (' ' + ' ' * (26 - phone.length)) + 't: ' + phone
173
+ out << tel + "\n"
174
+ out << ('-' * 30)
175
+
176
+ end
177
+
178
+ end
179
+
180
+ puts out.join("\n")
181
+
182
+ end
115
183
 
116
184
  def save(filename=@filename)
117
-
185
+
118
186
  s = dx_to_s(@dx)
119
187
  FileX.write File.join(@path, filename), s
120
188
  @dx.save File.join(@path, filename.sub(/\.txt$/,'.xml'))
121
-
189
+
190
+ end
191
+
192
+ def to_dx()
193
+ @dx
122
194
  end
123
-
195
+
124
196
  def to_s()
125
197
  dx_to_s @dx
126
198
  end
@@ -128,9 +200,9 @@ class ContactsTxt
128
200
  private
129
201
 
130
202
  def dx_to_s(dx)
131
-
203
+
132
204
  rows = dx.all.map do |row|
133
-
205
+
134
206
  h = row.to_h
135
207
 
136
208
  fullname = h.delete :fullname
@@ -140,11 +212,11 @@ class ContactsTxt
140
212
 
141
213
  ([fullname] + a.map {|x| x.join(': ') }).join("\n")
142
214
  end
143
-
215
+
144
216
  "<?contacts fields='%s'?>\n\n%s" % [@fields, rows.join("\n\n")]
145
-
217
+
146
218
  end
147
-
219
+
148
220
  def import_to_dx(raw_s)
149
221
 
150
222
  s = if raw_s =~ /<?contacts / then
@@ -156,35 +228,97 @@ class ContactsTxt
156
228
  found = s2[/(?<=#{keyword}=['"])[^'"]+/]
157
229
  found ? r.merge(keyword.to_sym => found) : r
158
230
  end
159
-
231
+
160
232
  h = {
161
- fields: @fields.join(', '),
162
- }.merge attributes
233
+ fields: @fields.join(', '),
234
+ }.merge attributes
163
235
 
164
- @fields = h[:fields].split(/ *, */)
236
+ @fields = h[:fields].split(/ *, */)
165
237
 
166
238
  if h[:root] then
167
- "\n\n" + h[:root] + "\n" +
239
+ "\n\n" + h[:root] + "\n" +
168
240
  raw_contacts.strip.lines.map {|line| ' ' + line}.join
169
241
  else
170
242
  raw_contacts
171
243
  end
172
-
244
+
173
245
  else
174
-
246
+
175
247
  raw_s.lstrip.lines[2..-1].join.strip
176
248
 
177
249
  end
178
250
 
179
251
  new_dx().import "--+\n" + s.split(/\s+(?=^[\w\s\(\)]+$)/)\
180
- .map {|x| 'fullname: ' + x }.join("\n")
181
-
252
+ .map {|x| 'fullname: ' + x }.join("\n")
253
+
182
254
  end
183
-
255
+
184
256
  def new_dx()
185
-
257
+
186
258
  Dynarex.new "contacts/contact(#{@fields.join ', '})"
187
-
259
+
260
+ end
261
+
262
+ end
263
+
264
+ class ContactsTxtAgent < ContactsTxt
265
+
266
+ def find_mobile_by_name(s)
267
+
268
+ result = find_by_name(s)
269
+
270
+ r = validate(result)
271
+
272
+ numbers = [r.sms.empty? ? r.mobile : r.sms, r.mobile].uniq\
273
+ .map {|x| x.sub(/\([^\)]+\)/,'').strip}
274
+
275
+ h = {}
276
+ h[:msg] = if numbers.length > 1 then
277
+ "The SMS number for %s is %s and the mobile number is %s" % \
278
+ [r.fullname, *numbers]
279
+ elsif numbers.first.length > 0 then
280
+ "The mobile number for %s is %s" % [r.fullname, numbers.first]
281
+ elsif r.tel.length > 0 then
282
+ "I don't have a mobile number, but the landline telephone " + \
283
+ "number for %s is %s" % [r.fullname, r.tel]
284
+ else
285
+ "I don't have a telephone number for " + r.fullname
286
+ end
287
+
288
+ h[:tags] = r.tags.to_s
289
+ h
290
+ end
291
+
292
+ def find_tel_by_name(s)
293
+
294
+ result = find_by_name(s)
295
+ r = validate(result)
296
+
297
+ h = {}
298
+
299
+ if r.tel.empty? then
300
+ return find_mobile_by_name(s)
301
+ else
302
+ h[:msg] = "The telephone number for %s is %s" % [r.fullname, r.tel]
303
+ end
304
+
305
+ h[:tags] = r.tags.to_s
306
+ h
307
+ end
308
+
309
+ private
310
+
311
+ def validate(result)
312
+
313
+ case result.class.to_s
314
+ when 'RecordX'
315
+ result
316
+ when 'Array'
317
+ result.first
318
+ when 'NilClass'
319
+ return "I couldn't find that name."
320
+ end
321
+
188
322
  end
189
323
 
190
324
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contacts_txt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.11
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Robertson
@@ -10,27 +10,32 @@ bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIDXjCCAkagAwIBAgIBATANBgkqhkiG9w0BAQUFADAsMSowKAYDVQQDDCFnZW1t
14
- YXN0ZXIvREM9amFtZXNyb2JlcnRzb24vREM9ZXUwHhcNMTgwODAxMjEwNzA0WhcN
15
- MTkwODAxMjEwNzA0WjAsMSowKAYDVQQDDCFnZW1tYXN0ZXIvREM9amFtZXNyb2Jl
16
- cnRzb24vREM9ZXUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC9696
17
- mu8TEN1NeSExgfozGbuajnFfKg3O4ipvtmz5qaM2BmYgxtsq/Y3JvcOmBmjXWJlL
18
- pH7PoEWZvonazT/HqYdKu9yihQ3tN5Ke/A9XvJwcz6Ug94LO0N8KgByLEBxRmSP1
19
- BYL8EpWJnhlNAffEdirPBcCLHvDl2S6RbDXyUWa03+qw6zK+Iuu9mcWoQdSxBrwU
20
- jD18mgNpVipsL1NT/dV2uz5LIESdYVA6kxvSwL2aGZ8O9c7XI8hl/9DNntRXB6BI
21
- qJ5PuYUBZVy3kOI4Ks4ra/QgaRcAGeH8f7Vl2A9SdLIYjP45CQyanHy6M8cmuwm1
22
- nSRHWQx/q3I8DhRdAgMBAAGjgYowgYcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAw
23
- HQYDVR0OBBYEFBgkPuVzdzsTk+wKFFCEXg7Lb9ZyMCYGA1UdEQQfMB2BG2dlbW1h
24
- c3RlckBqYW1lc3JvYmVydHNvbi5ldTAmBgNVHRIEHzAdgRtnZW1tYXN0ZXJAamFt
25
- ZXNyb2JlcnRzb24uZXUwDQYJKoZIhvcNAQEFBQADggEBAGoMpMeiWATe9UNHf317
26
- WRymCKIukfzFSTjwg/yc67F/qk5P23BdYywy7TA/l8M3L52+Cav3ZjiyquvkLDTX
27
- xNXGFArD5J5Wu/GN6I5vSLYwzC0G/iN4ZOffa3lpdxtqU0BWk1PgrMKSBYM22wCD
28
- Q1V22nUmZshq07vu1naaJvnmQe5SrXdNAwNue9xXHpAXRStGq3OgEtWl7k8MCPpr
29
- G//X20IZZXsvN64DFHpFyhz7JZTiTuyH+GkH/3BpwwTrz5Fv1f4nPpYg2Jxka1B5
30
- Ms9N9IXVzqxWl6qaGY7lENrLhETsyyvXsYq+Djcg8A9Fvn3Fk3do1ooh9ePNno3a
31
- 1G4=
13
+ MIIEXjCCAsagAwIBAgIBATANBgkqhkiG9w0BAQsFADAsMSowKAYDVQQDDCFnZW1t
14
+ YXN0ZXIvREM9amFtZXNyb2JlcnRzb24vREM9ZXUwHhcNMjIwMjIzMTk0ODIwWhcN
15
+ MjMwMjIzMTk0ODIwWjAsMSowKAYDVQQDDCFnZW1tYXN0ZXIvREM9amFtZXNyb2Jl
16
+ cnRzb24vREM9ZXUwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDlecEA
17
+ 1V+ZCFfCwQwbOZ9S2Tn+ggDp85hVOoHZyfA+E6MMOShj1CE22RDfbyrAal+Z01C5
18
+ dol4wfM2s3x3QGwU/BhwoBs1el3beCkqEf86/bAfBMZ7TsxP8NcxeaQYxd4XUW52
19
+ f0UTA6EgM65L4F+K6vBWD76vjHwO6Z+hF9BrVVvifuT1jNykZ/PoDncs4nZaQKFP
20
+ yCtrrfjq9WOVG+ueHSm1+7rWqxBO2jH95Nlyfe2t2Q27gOz4hpcU6tyCGEb5Liz/
21
+ za+SUVNKbv8kxVBoQYYDMyHgZeS5YN1qlkxXSjSrUAIpp4eUHxaKMo6lTcXPXRPA
22
+ CezHTFC1cn276L80YXTj0Gw2Jp9On2AJXifKZ11nlOs+gBSS32r8UiqptAGe97Py
23
+ PotM+fYUjH7yunVnvsPIN+EC08vAhXCrMfFnvCuuyeSv8KKUFxmIeZE1Fn29MooE
24
+ Qd6QI6SJGWQ918Vj1NE4Lo/EKtgl5opL4cVPRzrH7yH82oyQiI/7NiemwrMCAwEA
25
+ AaOBijCBhzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUaABOt2ER
26
+ TZ9I1b5uj7HkRf+YVr4wJgYDVR0RBB8wHYEbZ2VtbWFzdGVyQGphbWVzcm9iZXJ0
27
+ c29uLmV1MCYGA1UdEgQfMB2BG2dlbW1hc3RlckBqYW1lc3JvYmVydHNvbi5ldTAN
28
+ BgkqhkiG9w0BAQsFAAOCAYEABS1c63h+vQL2hjWs7BvQM6vFxp1T4RDvviUqLUBt
29
+ YAg1/vWquUZ0PVi+Hf9gAaSumDjBb7qbbkn3Y2j/aV7wpG/yFtBoknIqihp7oH7/
30
+ wqGlntx9baORy7chaaBRA4CB4gGUFQ0wYHCBrHmj9zvfFWXnnRoFa06JIHm2DmOB
31
+ 41DwQiiLflNj4iYbLzNQSI5X0iRu3H8zcAp45HJNF2LBrY32b8U+4Uf1w9QOJ4Io
32
+ bXdjMDxNnHEj2+V2yaq4J8v0o/xEE0Qv2TEeXyiv2fvIRz5VsS3ayYv+rHVmxGuo
33
+ VuXOnyLlTUjeB0IakaSYdBFWW3uno+fds/mIBL9VtmZzPJ4UhirVs0t4GvftJ2oT
34
+ weBCjBPmFwYPtn66vFgOaUHK421yIA2FC+AQO/pOOSgngHz0pm08NMpcTeTaufKu
35
+ x9gWyaB0gatLOaqUuwj8jCICpzNLo20JZQyEav2hZDxdB1EQjxq9jZrMaxwW3lF/
36
+ zHoZFKaw47O+Nd14HCqMVZUt
32
37
  -----END CERTIFICATE-----
33
- date: 2019-02-13 00:00:00.000000000 Z
38
+ date: 2022-02-23 00:00:00.000000000 Z
34
39
  dependencies:
35
40
  - !ruby/object:Gem::Dependency
36
41
  name: dynarex
@@ -38,22 +43,22 @@ dependencies:
38
43
  requirements:
39
44
  - - "~>"
40
45
  - !ruby/object:Gem::Version
41
- version: '1.8'
46
+ version: '1.9'
42
47
  - - ">="
43
48
  - !ruby/object:Gem::Version
44
- version: 1.8.15
49
+ version: 1.9.6
45
50
  type: :runtime
46
51
  prerelease: false
47
52
  version_requirements: !ruby/object:Gem::Requirement
48
53
  requirements:
49
54
  - - "~>"
50
55
  - !ruby/object:Gem::Version
51
- version: '1.8'
56
+ version: '1.9'
52
57
  - - ">="
53
58
  - !ruby/object:Gem::Version
54
- version: 1.8.15
59
+ version: 1.9.6
55
60
  description:
56
- email: james@jamesrobertson.eu
61
+ email: digital.robertson@gmail.com
57
62
  executables: []
58
63
  extensions: []
59
64
  extra_rdoc_files: []
@@ -78,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
83
  - !ruby/object:Gem::Version
79
84
  version: '0'
80
85
  requirements: []
81
- rubygems_version: 3.0.2
86
+ rubygems_version: 3.2.22
82
87
  signing_key:
83
88
  specification_version: 4
84
89
  summary: Reads a contacts.txt file
metadata.gz.sig CHANGED
Binary file