hulaki 0.1 → 1.0.2
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 +4 -4
- data/Gemfile.lock +17 -7
- data/README.md +74 -20
- data/hulaki.gemspec +23 -16
- data/images/hulaki.png +0 -0
- data/lib/hulaki.rb +8 -76
- data/lib/hulaki/config/config.rb +22 -22
- data/lib/hulaki/config/sample.config.yml +34 -0
- data/lib/hulaki/config/sample.contact.csv +4 -0
- data/lib/hulaki/config/sample.template.html.erb +10 -0
- data/lib/hulaki/contact_parser.rb +9 -13
- data/lib/hulaki/core.rb +90 -0
- data/lib/hulaki/{email_validator.rb → email_handler/email_validator.rb} +3 -3
- data/lib/hulaki/email_handler/mailer.rb +73 -0
- data/lib/hulaki/option_parser.rb +77 -67
- data/lib/hulaki/presenter.rb +15 -9
- data/lib/hulaki/recursive_ostruct.rb +12 -0
- data/lib/hulaki/search_engine.rb +19 -10
- data/lib/hulaki/sms_handler/gateway_adapters/nexmo.rb +21 -0
- data/lib/hulaki/sms_handler/gateway_adapters/twilio.rb +8 -19
- data/lib/hulaki/sms_handler/sms_handler.rb +23 -14
- data/lib/hulaki/sms_handler/sms_validator.rb +3 -8
- data/lib/hulaki/string_modifier.rb +4 -0
- data/lib/hulaki/utils.rb +76 -0
- data/lib/hulaki/version.rb +1 -1
- metadata +79 -19
- data/lib/hulaki/config/config_sample.yml +0 -25
- data/lib/hulaki/mailer.rb +0 -59
data/lib/hulaki/search_engine.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'amatch'
|
2
|
+
|
1
3
|
class Hulaki::SearchEngine
|
2
4
|
include Amatch
|
3
5
|
|
@@ -15,27 +17,34 @@ class Hulaki::SearchEngine
|
|
15
17
|
private
|
16
18
|
|
17
19
|
def search(data)
|
18
|
-
result = search_result(data).select { |x| x[1] > 0.
|
20
|
+
result = search_result(data).select { |x| x[1] > 0.4 } # setting threshold
|
21
|
+
# Sort data keeping data with higer degree of similarity at the top
|
22
|
+
# i.e. having lowest value of percentage at the bottom
|
19
23
|
result.sort { |x, y| y[1] <=> x[1] }
|
20
24
|
end
|
21
25
|
|
22
26
|
def search_result(data)
|
27
|
+
downcased_data = data.downcase.gsub(' ', '')
|
23
28
|
@csv_data.map do |row|
|
24
|
-
|
25
|
-
row.each do |
|
26
|
-
keys_to_search.each do |key|
|
27
|
-
if
|
28
|
-
|
29
|
+
max_point = 0.0
|
30
|
+
row.each do |col_head, v|
|
31
|
+
keys_to_search.each do |key, weight|
|
32
|
+
if col_head.to_s.downcase == key
|
33
|
+
point = PairDistance.new(v.to_s.downcase).match(downcased_data)*weight
|
34
|
+
max_point = point if max_point < point
|
35
|
+
# puts "#{key} #{col_head} #{point} #{v} #{downcased_data}"
|
29
36
|
end
|
30
37
|
end
|
31
38
|
end
|
32
|
-
|
33
|
-
|
34
|
-
[row, percentage]
|
39
|
+
|
40
|
+
[row, max_point]
|
35
41
|
end
|
36
42
|
end
|
37
43
|
|
38
44
|
def keys_to_search
|
39
|
-
|
45
|
+
{
|
46
|
+
'name' => 2, 'first_name' => 3, 'last_name' => 3, 'given_name' => 3,
|
47
|
+
'family_name' => 3, 'email' => 0.6, 'phone_1___value'=> 0.5, 'phone_2___value' => 0.5
|
48
|
+
}
|
40
49
|
end
|
41
50
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'nexmo'
|
2
|
+
|
3
|
+
class Hulaki::Nexmo
|
4
|
+
attr_reader :to, :from, :message, :client
|
5
|
+
|
6
|
+
def initialize(params = {})
|
7
|
+
@to = params[:to]
|
8
|
+
@message = params[:message]
|
9
|
+
|
10
|
+
@config = params[:config]
|
11
|
+
@from = params.fetch(:from, @config['from'])
|
12
|
+
return true if ENV['mode'] == 'test'
|
13
|
+
@client = Nexmo::Client.new(key: @config['API_KEY'], secret: @config['API_SECRET'])
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def send
|
18
|
+
return true if ENV['mode'] == 'test'
|
19
|
+
client.send_message(from: from, to: to, text: message)
|
20
|
+
end
|
21
|
+
end
|
@@ -1,35 +1,24 @@
|
|
1
|
+
require 'twilio-ruby'
|
2
|
+
|
1
3
|
class Hulaki::Twilio
|
2
4
|
attr_reader :to, :from, :message
|
3
5
|
|
4
6
|
def initialize(params = {})
|
5
|
-
@to
|
7
|
+
@to = params[:to]
|
6
8
|
@message = params[:message]
|
7
9
|
|
8
|
-
@config
|
9
|
-
@from
|
10
|
-
@client
|
11
|
-
@config['
|
10
|
+
@config = params[:config]
|
11
|
+
@from = @config['ACCOUNT_PHONE_NUMBER']
|
12
|
+
@client = Twilio::REST::Client.new @config['API_KEY'],
|
13
|
+
@config['API_SECRET']
|
12
14
|
end
|
13
15
|
|
14
16
|
def send
|
15
|
-
return true if
|
17
|
+
return true if ENV['mode'] == 'test'
|
16
18
|
@client.messages.create(
|
17
19
|
from: from,
|
18
20
|
to: to,
|
19
21
|
body: message
|
20
22
|
)
|
21
23
|
end
|
22
|
-
|
23
|
-
class << self
|
24
|
-
@@mode = 'live'
|
25
|
-
|
26
|
-
def mode=(mode)
|
27
|
-
@@mode = mode
|
28
|
-
end
|
29
|
-
|
30
|
-
def mode
|
31
|
-
@@mode
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
24
|
end
|
@@ -1,13 +1,16 @@
|
|
1
1
|
class Hulaki::SmsHandler
|
2
|
+
VALID_GATEWAY = ['twilio', 'nexmo', 'sparrow']
|
2
3
|
attr_reader :gateway, :to, :from, :message
|
3
4
|
|
4
5
|
def initialize(params = {})
|
5
|
-
@to
|
6
|
-
@from
|
6
|
+
@to = params.fetch(:to, params[:recipient])
|
7
|
+
@from = params.fetch(:from, params[:sender])
|
7
8
|
@message = params.fetch(:message, params[:msg])
|
8
9
|
|
9
|
-
|
10
|
+
explicit_gateway = params[:gateway] && VALID_GATEWAY.include?(params[:gateway].downcase) && params[:gateway].downcase
|
10
11
|
|
12
|
+
@gateway_name = explicit_gateway || get_default_gateway_name
|
13
|
+
@gateway = get_gateway
|
11
14
|
end
|
12
15
|
|
13
16
|
def send
|
@@ -17,19 +20,16 @@ class Hulaki::SmsHandler
|
|
17
20
|
|
18
21
|
private
|
19
22
|
|
20
|
-
def get_gateway
|
23
|
+
def get_gateway
|
21
24
|
config = gateway_config
|
22
|
-
|
23
|
-
gateway_name ||= config['name']
|
24
|
-
|
25
|
-
klass = gateway_name.to_s.capitalize
|
25
|
+
klass = @gateway_name.to_s.capitalize
|
26
26
|
|
27
27
|
eval("Hulaki::#{klass}").new(
|
28
28
|
{
|
29
|
-
config
|
30
|
-
to
|
31
|
-
from
|
32
|
-
message
|
29
|
+
:config => gateway_config,
|
30
|
+
:to => to,
|
31
|
+
:from => from || gateway_config['from'],
|
32
|
+
:message => message
|
33
33
|
})
|
34
34
|
|
35
35
|
rescue SyntaxError => e
|
@@ -38,11 +38,20 @@ class Hulaki::SmsHandler
|
|
38
38
|
|
39
39
|
def verify_details
|
40
40
|
Hulaki::SmsValidator.new(to: to,
|
41
|
-
from: from || gateway_config['
|
41
|
+
from: from || gateway_config['ACCOUNT_PHONE_NUMBER'],
|
42
42
|
message: message).validate
|
43
43
|
end
|
44
44
|
|
45
|
+
def get_default_gateway_name
|
46
|
+
Hulaki::Config['sms'].each do|key, value|
|
47
|
+
return key if value['default'] == true
|
48
|
+
end
|
49
|
+
|
50
|
+
# If no default defined in the config; pick the last one
|
51
|
+
Hulaki::Config['sms'].keys.last
|
52
|
+
end
|
53
|
+
|
45
54
|
def gateway_config
|
46
|
-
Hulaki::Config
|
55
|
+
@gateway_config ||= Hulaki::Config['sms'][@gateway_name]
|
47
56
|
end
|
48
57
|
end
|
@@ -3,15 +3,13 @@ class Hulaki::SmsValidator
|
|
3
3
|
RegexPhoneNumber = /(?:\+?|\b)[0-9]{10}\b/
|
4
4
|
|
5
5
|
def initialize(params = {})
|
6
|
-
@errors
|
7
|
-
@to
|
8
|
-
@from = params.fetch(:from, params[:sender])
|
6
|
+
@errors = {}
|
7
|
+
@to = params.fetch(:to, params[:recipient])
|
9
8
|
@message = params.fetch(:message, params[:msg])
|
10
9
|
end
|
11
10
|
|
12
11
|
def validate
|
13
|
-
to
|
14
|
-
from || (raise Hulaki::InvalidPhoneNumber, 'Sender phone number should be present.')
|
12
|
+
to || (raise Hulaki::InvalidPhoneNumber, 'Recipient phone number should be present.')
|
15
13
|
message || (raise Hulaki::InvalidMessageBody, 'Message body should be present.')
|
16
14
|
|
17
15
|
check_if_number_invalid
|
@@ -29,9 +27,6 @@ class Hulaki::SmsValidator
|
|
29
27
|
def check_if_number_invalid
|
30
28
|
RegexPhoneNumber.match(to) || (raise Hulaki::InvalidPhoneNumber,
|
31
29
|
"Phone number '#{to}' is invalid.")
|
32
|
-
|
33
|
-
RegexPhoneNumber.match(from) || (raise Hulaki::InvalidPhoneNumber,
|
34
|
-
"Phone number '#{from}' is invalid.")
|
35
30
|
end
|
36
31
|
|
37
32
|
end
|
@@ -2,7 +2,11 @@ class String
|
|
2
2
|
def black; "\e[30m#{self}\e[0m" end
|
3
3
|
def red; "\e[31m#{self}\e[0m" end
|
4
4
|
def green; "\e[32m#{self}\e[0m" end
|
5
|
+
def brown; "\e[33m#{self}\e[0m" end
|
5
6
|
def blue; "\e[34m#{self}\e[0m" end
|
7
|
+
def magenta; "\e[35m#{self}\e[0m" end
|
8
|
+
def cyan; "\e[36m#{self}\e[0m" end
|
9
|
+
def gray; "\e[37m#{self}\e[0m" end
|
6
10
|
|
7
11
|
def bg_black; "\e[40m#{self}\e[0m" end
|
8
12
|
def bg_red; "\e[41m#{self}\e[0m" end
|
data/lib/hulaki/utils.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module Utils
|
2
|
+
def create_dir
|
3
|
+
FileUtils.mkdir(File.expand_path('~/hulaki'))
|
4
|
+
rescue Errno::EEXIST
|
5
|
+
puts 'Looks like directory `~/hulaki` already exists.'.brown
|
6
|
+
end
|
7
|
+
|
8
|
+
def install_dependencies
|
9
|
+
if `which xclip`.match('not found')
|
10
|
+
puts "Looks like you don't `xclip` installed in your system. It is required to copy phone numbers to ClipBoard"
|
11
|
+
puts 'We are installing it right now ... '
|
12
|
+
puts 'It will ask you password: Be ready'
|
13
|
+
puts `sudo apt-get install xclip`.red
|
14
|
+
puts '`xclip` successfully installed!'.green
|
15
|
+
else
|
16
|
+
puts '`xclip` is already installed!'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def start_copying_file
|
21
|
+
# this line is for debugging purposes
|
22
|
+
this_file = __FILE__
|
23
|
+
files_to_be_copied = {
|
24
|
+
'sample.contact.csv' => 'contact.csv',
|
25
|
+
'sample.config.yml' => 'config.yml',
|
26
|
+
'sample.template.html.erb' => 'template.html.erb'
|
27
|
+
}
|
28
|
+
|
29
|
+
# Start copying the files
|
30
|
+
files_to_be_copied.each do|source, dest|
|
31
|
+
file_path = File.expand_path("../../lib/hulaki/config/#{source}", File.dirname(this_file))
|
32
|
+
desc_file = File.expand_path("~/hulaki/#{dest}")
|
33
|
+
if File.exist?(desc_file)
|
34
|
+
puts "Looks like the file '#{desc_file}' already exists.".brown
|
35
|
+
print 'Shall we forcefully override the file?(yes/no)'.brown
|
36
|
+
handle_conflict(file_path, desc_file)
|
37
|
+
else
|
38
|
+
copy_file(file_path, desc_file)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
Hulaki::Logger.log '~'*100
|
42
|
+
Hulaki::Logger.log 'Please make sure you have modified the files at `~/hulaki` a/c to your need.'
|
43
|
+
Hulaki::Logger.log '~'*100
|
44
|
+
end
|
45
|
+
|
46
|
+
def handle_conflict(file_path, desc_file)
|
47
|
+
input = gets().chomp()
|
48
|
+
if %w{yes y}.include?(input.downcase)
|
49
|
+
copy_file(file_path, desc_file)
|
50
|
+
else
|
51
|
+
Hulaki::Logger.log 'You choose to leave it as it is.'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def copy_file(file_path, desc_file)
|
56
|
+
puts "Creating file '#{desc_file}' ...".brown
|
57
|
+
FileUtils.cp(file_path, desc_file)
|
58
|
+
Hulaki::Logger.log "Created file '#{desc_file}' ..."
|
59
|
+
end
|
60
|
+
|
61
|
+
def present(object)
|
62
|
+
object.to_s.split("\n").map{|x|
|
63
|
+
if x[0] == '#'
|
64
|
+
x.gray
|
65
|
+
elsif x[0] == '$'
|
66
|
+
x.green
|
67
|
+
elsif x.match('---')
|
68
|
+
x.brown
|
69
|
+
else
|
70
|
+
x
|
71
|
+
end
|
72
|
+
}.join("\n")
|
73
|
+
end
|
74
|
+
|
75
|
+
module_function :create_dir, :start_copying_file, :handle_conflict, :copy_file, :install_dependencies, :present
|
76
|
+
end
|
data/lib/hulaki/version.rb
CHANGED
metadata
CHANGED
@@ -1,17 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hulaki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shiva Bhusal
|
8
|
-
- Shishir Sapkota
|
9
|
-
- Neha Suwal
|
10
|
-
- Prativa Devkota
|
11
8
|
autorequire:
|
12
9
|
bindir: exe
|
13
10
|
cert_chain: []
|
14
|
-
date:
|
11
|
+
date: 2017-06-01 00:00:00.000000000 Z
|
15
12
|
dependencies:
|
16
13
|
- !ruby/object:Gem::Dependency
|
17
14
|
name: bundler
|
@@ -73,16 +70,16 @@ dependencies:
|
|
73
70
|
name: amatch
|
74
71
|
requirement: !ruby/object:Gem::Requirement
|
75
72
|
requirements:
|
76
|
-
- - "
|
73
|
+
- - "~>"
|
77
74
|
- !ruby/object:Gem::Version
|
78
|
-
version:
|
75
|
+
version: 0.3.1
|
79
76
|
type: :runtime
|
80
77
|
prerelease: false
|
81
78
|
version_requirements: !ruby/object:Gem::Requirement
|
82
79
|
requirements:
|
83
|
-
- - "
|
80
|
+
- - "~>"
|
84
81
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
82
|
+
version: 0.3.1
|
86
83
|
- !ruby/object:Gem::Dependency
|
87
84
|
name: twilio-ruby
|
88
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -97,20 +94,76 @@ dependencies:
|
|
97
94
|
- - "~>"
|
98
95
|
- !ruby/object:Gem::Version
|
99
96
|
version: 4.11.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: nexmo
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 4.6.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 4.6.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: mail
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 2.6.3
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 2.6.3
|
100
125
|
- !ruby/object:Gem::Dependency
|
101
126
|
name: smarter_csv
|
102
127
|
requirement: !ruby/object:Gem::Requirement
|
103
128
|
requirements:
|
104
|
-
- -
|
129
|
+
- - '='
|
105
130
|
- !ruby/object:Gem::Version
|
106
|
-
version:
|
131
|
+
version: 1.1.0
|
107
132
|
type: :runtime
|
108
133
|
prerelease: false
|
109
134
|
version_requirements: !ruby/object:Gem::Requirement
|
110
135
|
requirements:
|
111
|
-
- -
|
136
|
+
- - '='
|
112
137
|
- !ruby/object:Gem::Version
|
113
|
-
version:
|
138
|
+
version: 1.1.0
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: terminal-table
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - '='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 1.8.0
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - '='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 1.8.0
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: clipboard
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - '='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 1.1.0
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - '='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 1.1.0
|
114
167
|
description: We developers don't have time to grab mobile phones, slide
|
115
168
|
the screen, press pin numbers, open contact list and search
|
116
169
|
the person you are looking for. Instead it would me much
|
@@ -137,29 +190,36 @@ files:
|
|
137
190
|
- bin/setup
|
138
191
|
- exe/hulaki
|
139
192
|
- hulaki.gemspec
|
193
|
+
- images/hulaki.png
|
140
194
|
- lib/hulaki.rb
|
141
195
|
- lib/hulaki/config/config.rb
|
142
|
-
- lib/hulaki/config/
|
196
|
+
- lib/hulaki/config/sample.config.yml
|
197
|
+
- lib/hulaki/config/sample.contact.csv
|
198
|
+
- lib/hulaki/config/sample.template.html.erb
|
143
199
|
- lib/hulaki/contact_parser.rb
|
144
|
-
- lib/hulaki/
|
200
|
+
- lib/hulaki/core.rb
|
201
|
+
- lib/hulaki/email_handler/email_validator.rb
|
202
|
+
- lib/hulaki/email_handler/mailer.rb
|
145
203
|
- lib/hulaki/exceptions.rb
|
146
204
|
- lib/hulaki/logger.rb
|
147
|
-
- lib/hulaki/mailer.rb
|
148
205
|
- lib/hulaki/option_parser.rb
|
149
206
|
- lib/hulaki/presenter.rb
|
150
207
|
- lib/hulaki/recursive_ostruct.rb
|
151
208
|
- lib/hulaki/search_engine.rb
|
209
|
+
- lib/hulaki/sms_handler/gateway_adapters/nexmo.rb
|
152
210
|
- lib/hulaki/sms_handler/gateway_adapters/sparrow.rb
|
153
211
|
- lib/hulaki/sms_handler/gateway_adapters/twilio.rb
|
154
212
|
- lib/hulaki/sms_handler/sms_handler.rb
|
155
213
|
- lib/hulaki/sms_handler/sms_validator.rb
|
156
214
|
- lib/hulaki/string_modifier.rb
|
215
|
+
- lib/hulaki/utils.rb
|
157
216
|
- lib/hulaki/version.rb
|
158
217
|
homepage: https://github.com/shivabhusal/hulaki
|
159
218
|
licenses:
|
160
219
|
- MIT
|
161
220
|
metadata: {}
|
162
|
-
post_install_message:
|
221
|
+
post_install_message: Please run `$ hulaki -i` to install Configuration files so that
|
222
|
+
you can modify later
|
163
223
|
rdoc_options: []
|
164
224
|
require_paths:
|
165
225
|
- lib
|
@@ -175,9 +235,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
175
235
|
version: '0'
|
176
236
|
requirements: []
|
177
237
|
rubyforge_project:
|
178
|
-
rubygems_version: 2.
|
238
|
+
rubygems_version: 2.6.12
|
179
239
|
signing_key:
|
180
240
|
specification_version: 4
|
181
241
|
summary: Hulaki is basically a CLI tool to search contact details \ exported already
|
182
|
-
in CSV format.
|
242
|
+
in CSV format, send SMS and Emails in a single command.
|
183
243
|
test_files: []
|