blackstack_commons 0.0.6 → 0.0.7

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
  SHA1:
3
- metadata.gz: 3aec128e1a1eec0e0a227cb1ce7c8ea7dec098ba
4
- data.tar.gz: 4c0d2d53a5496caae389469a135840d5e347035f
3
+ metadata.gz: e5f9a516f584be61a23ccf4a8e49cc5f62c0f8ca
4
+ data.tar.gz: a75e5f139c87961a3d03f1ea4d9e5c06fb2c060a
5
5
  SHA512:
6
- metadata.gz: b112efb7373ce759aa62bdf003c358d29a0d8a343f80609bb7d33587c2aa775b8764d0c74b2d94bccbabf3243eef9de8c244f432037c5223ced556f9dd478eb3
7
- data.tar.gz: e9151c5041d409ced876f294f4e4d0323d52974ba136bcb83cec3d8bf2e89e00ecc5965b4654e0ef572b8174eb142e6c9698147fdc519b5ed9505421a0b830c2
6
+ metadata.gz: 8491e3bc4478a58267fec9979dd823398d0cc1a3642db74933c19c764dd70ab32e6a10727f70694d070e18417db7b76b6559d01f138d5262a8d7c9ed4002c6e9
7
+ data.tar.gz: b68d4a2df8db3b240b016e80cb6366714e262f7a7eb9f4d56e28fe887bd970f760a373116c0cca9b6882d794de9f42bc8c07b91b66515472e1781df193df9427
@@ -0,0 +1,290 @@
1
+ require_relative '../lib/blackstack_commons'
2
+
3
+ # returns true if the string meets all the security requirements for a password
4
+ puts ""
5
+ puts "Passwords"
6
+ a = ['Hello', 'HelloWorld12$3']
7
+ a.each { |s|
8
+ print "'#{s}'.password?... "
9
+ puts s.password?.to_s
10
+ }
11
+
12
+ # returns true if the string match with the regex of a GUID
13
+ puts ""
14
+ puts "GUIDs"
15
+ a = [
16
+ '{331a92c3-5fe1-47a2-a31b-cfa439b5b4f9}',
17
+ '331a92c3-5fe1-47a2-a31b-cfa439b5b4f9',
18
+ '{331A92C3-5FE1-47A2-A31B-CFA439B5B4F9}',
19
+ '331A92C3-5FE1-47A2-A31B-CFA439B5B4F9',
20
+ '331A92C35FE147A2A31BCFA439B5B4F9',
21
+ ]
22
+ a.each { |s|
23
+ print "'#{s}'.guid?... "
24
+ puts s.guid?.to_s
25
+ }
26
+
27
+ # returns true if the string match with the regex of a filename
28
+ puts ""
29
+ puts "Filenames"
30
+ a = [
31
+ 'filename.txt',
32
+ 'filename',
33
+ 'filename.txt.rar',
34
+ ]
35
+ a.each { |s|
36
+ print "'#{s}'.filename?... "
37
+ puts s.filename?.to_s
38
+ }
39
+
40
+ # returns true if the string match with the regex of an email
41
+ puts ""
42
+ puts "Emails"
43
+ a = [
44
+ 'tango@expandedventure.com',
45
+ 'tango@expandedventure.com.ar',
46
+ 'tango',
47
+ 'tango@',
48
+ ]
49
+ a.each { |s|
50
+ print "'#{s}'.email?... "
51
+ puts s.email?.to_s
52
+ }
53
+
54
+ # returns true if the string match with the regex of a domain
55
+ puts ""
56
+ puts "Domains"
57
+ a = [
58
+ 'tango',
59
+ 'tango@expandedventure',
60
+ 'tango@expandedventure.com',
61
+ 'tango@expandedventure.com.ar',
62
+ 'expandedventure.com',
63
+ 'expandedventure.com.ar',
64
+ 'https://expandedventure.com.ar',
65
+ 'www.expandedventure.com.ar',
66
+ 'https://www.expandedventure.com.ar',
67
+ ]
68
+ a.each { |s|
69
+ print "'#{s}'.domain?... "
70
+ puts s.domain?.to_s
71
+ }
72
+
73
+ # returns true if the string match with the regex of a phone number
74
+ puts ""
75
+ puts "Domains"
76
+ a = [
77
+ '+54 9 11 5061 2148',
78
+ '545-5561-2148',
79
+ '545-561-2148',
80
+ '545 561 2148',
81
+ '54 545 561 2148',
82
+ '+54 545 561 2148',
83
+ '+54 545-561-2148',
84
+ '+54-545-561-2148',
85
+ ]
86
+ a.each { |s|
87
+ print "'#{s}'.domain?... "
88
+ puts s.phone?.to_s
89
+ }
90
+
91
+ # returns true if the string match with the regex of a URL
92
+ puts ""
93
+ puts "URLs"
94
+ a = [
95
+ 'tango',
96
+ 'tango@expandedventure',
97
+ 'tango@expandedventure.com',
98
+ 'tango@expandedventure.com.ar',
99
+ 'expandedventure.com',
100
+ 'expandedventure.com.ar',
101
+ 'https://expandedventure.com.ar',
102
+ 'www.expandedventure.com.ar',
103
+ 'https://www.expandedventure.com.ar',
104
+ ]
105
+ a.each { |s|
106
+ print "'#{s}'.url?... "
107
+ puts s.url?.to_s
108
+ }
109
+
110
+ # returns true if the string match with the regex of a number
111
+ puts ""
112
+ puts "Fixnums"
113
+ a = [
114
+ '5',
115
+ '5.5',
116
+ '5,5',
117
+ '5000',
118
+ '5,000',
119
+ '5.000',
120
+ ]
121
+ a.each { |s|
122
+ print "'#{s.to_s}'.fixnum?... "
123
+ puts s.fixnum?.to_s
124
+ }
125
+
126
+ # returns true if the string match with the regex of a datetime used in the BlackStack's API
127
+ puts ""
128
+ puts "SQL DateTimes"
129
+ a = [
130
+ '20191106215030',
131
+ '20191106',
132
+ '2019-11-06',
133
+ '2019-11-06 21:50:30',
134
+ '2019-13-06 21:50:30', # invalid month
135
+ '2019-11-06 25:50:30', # invalid hour
136
+ '2019-11-06 21:70:30', # invalid minute
137
+ '2019-11-06 21:50:70', # invalid second
138
+ ]
139
+ a.each { |s|
140
+ print "'#{s.to_s}'.sql_datetime?... "
141
+ puts s.sql_datetime?.to_s
142
+ }
143
+
144
+ #
145
+ puts ""
146
+ puts "API DateTimes"
147
+ a = [
148
+ '20191106215030',
149
+ '20191106',
150
+ '2019-11-06',
151
+ '2019-11-06 21:50:30',
152
+ '20191306215030', # invalid month
153
+ '20191106255030', # invalid hour
154
+ '20191106217030', # invalid minute
155
+ '20191106215070', # invalid second
156
+ ]
157
+ a.each { |s|
158
+ print "'#{s.to_s}'.api_datetime?... "
159
+ puts s.api_datetime?.to_s
160
+ }
161
+
162
+ # Convierte un string con formato sql-datatime a un string con formato sql-datetime.
163
+ puts ""
164
+ puts "SQL DateTime -> API DateTime"
165
+ a = [
166
+ '2019-11-06 21:50:30',
167
+ ]
168
+ a.each { |s|
169
+ print "'#{s.to_s}'.sql_to_api_datetime... "
170
+ puts s.sql_to_api_datetime.to_s
171
+ }
172
+
173
+ # Convierte un string con formato api-datatime (yyyymmddhhmmss) a un string con formato sql-datetime (yyyy-mm-dd hh:mm:ss).
174
+ puts ""
175
+ puts "API DateTime -> SQL DateTime"
176
+ a = [
177
+ '20191106215030',
178
+ ]
179
+ a.each { |s|
180
+ print "'#{s.to_s}'.api_to_sql_datetime... "
181
+ puts s.api_to_sql_datetime.to_s
182
+ }
183
+
184
+ # Rewrite a GUID as a standard (normalized) format.
185
+ puts ""
186
+ puts "Any GUID -> Normalized Guid"
187
+ a = [
188
+ '{331a92c3-5fe1-47a2-a31b-cfa439b5b4f9}',
189
+ '331a92c3-5fe1-47a2-a31b-cfa439b5b4f9',
190
+ '{331A92C3-5FE1-47A2-A31B-CFA439B5B4F9}',
191
+ '331A92C3-5FE1-47A2-A31B-CFA439B5B4F9',
192
+ ]
193
+ a.each { |s|
194
+ print "'#{s}'.to_guid... "
195
+ puts s.to_guid.to_s
196
+ }
197
+
198
+ # Escape simple-quotes too add the string into literal-string of a dynamic query build into the Ruby code.
199
+ # Example: "I'm BlackStack" -> "I''m BlackStack"
200
+ puts ""
201
+ puts "Any String -> String with Escaped Quotes"
202
+ a = [
203
+ "I'm BlackStack",
204
+ "Hello World!",
205
+ ]
206
+ a.each { |s|
207
+ print "'#{s}'.to_sql... "
208
+ puts s.to_sql.to_s
209
+ }
210
+
211
+ #
212
+ puts ""
213
+ puts "Spintax"
214
+ a = [
215
+ "I'm BlackStack",
216
+ "Hello World!",
217
+ "{Hello|Hi} World!",
218
+ "{Hello|Hi|Good {Morning|Afternoon}} World!", # Nexted spintax. Not supported.
219
+ "{Hello|Hi World!", # wrong syntax.
220
+ ]
221
+ a.each { |s|
222
+ print "'#{s}'.spintax?... "
223
+ puts s.spintax?.to_s
224
+ }
225
+
226
+ # Returns a random spin from a spintax
227
+ puts ""
228
+ puts "Spin"
229
+ a = [
230
+ "{Hello|Hi|Good Morning|Good Afternoon} World!",
231
+ "{Hello|Hi|Good Morning|Good Afternoon} World!",
232
+ "{Hello|Hi|Good Morning|Good Afternoon} World!",
233
+ "{Hello|Hi|Good Morning|Good Afternoon} World!",
234
+ ]
235
+ a.each { |s|
236
+ print "'#{s}'.spin... "
237
+ puts s.spin
238
+ }
239
+
240
+ # Converts a time object to an SQL friendy string
241
+ puts ""
242
+ puts "Time object -> SQL"
243
+ a = [
244
+ Time.new(2019,11,6,15,25,55),
245
+ DateTime.new(2019,11,6,15,25,55),
246
+ ]
247
+ a.each { |o|
248
+ print "'#{o.to_s}'.to_sql... "
249
+ puts o.to_sql
250
+ }
251
+
252
+ # Converts number to a string with a format like xx,xxx,xxx.xxxx
253
+ puts ""
254
+ puts "Fixnum & Floats -> Screen Friendly Text"
255
+ a = [
256
+ 64443,
257
+ 64443.5454,
258
+ ]
259
+ a.each { |i|
260
+ print "'#{i.to_s}'.to_label... "
261
+ puts i.to_label
262
+ }
263
+
264
+ # Converts number to a string with a format like xx,xxx,xxx.xxxx
265
+ puts ""
266
+ puts "Fixnum Minutes -> Time Spent (days, hours, minutes)"
267
+ a = [
268
+ 59,
269
+ 60,
270
+ 61,
271
+ 600,
272
+ 601,
273
+ 1440,
274
+ 1441,
275
+ 1500,
276
+ 1501,
277
+ ]
278
+ a.each { |i|
279
+ print "Minutes '#{i.to_s}'.to_time_spent... "
280
+ puts i.to_time_spent
281
+ }
282
+
283
+
284
+ =begin # TODO: Pending
285
+ encode_string
286
+ encode_html
287
+ encode_exception
288
+ encode_period
289
+ encode_javascript
290
+ =end
@@ -0,0 +1,3 @@
1
+ require_relative '../lib/blackstack_commons'
2
+
3
+ BlackStack::Netting::api_call('https://connectionsphere.com/api1.4/ping.json')
data/lib/datetime.rb ADDED
@@ -0,0 +1,6 @@
1
+ class DateTime
2
+ # Converts a time object to an SQL friendy string
3
+ def to_sql()
4
+ BlackStack::DateTime::Encoding::datetime_to_sql(self)
5
+ end
6
+ end # class DateTime
data/lib/exception.rb ADDED
@@ -0,0 +1,5 @@
1
+ class Exception
2
+ def to_html
3
+ BlackStack::Strings::Encoding.encode_exception(self)
4
+ end
5
+ end
data/lib/fixnum.rb ADDED
@@ -0,0 +1,14 @@
1
+ class Fixnum
2
+ # Converts number to a string with a format like xx,xxx,xxx.xxxx
3
+ def to_label()
4
+ BlackStack::Number::Encoding::format_with_separator(self)
5
+ end
6
+
7
+ # Convierte una cantidad de minutos a una leyenda legible por el usuario.
8
+ # Ejemplo: "2 days, 5 hours"
9
+ # Ejemplo: "4 hours, 30 minutes"
10
+ # Ejemplo: "3 days, 4 hour"
11
+ def to_time_spent()
12
+ BlackStack::Number::Encoding::encode_minutes(self)
13
+ end
14
+ end # class String
data/lib/float.rb ADDED
@@ -0,0 +1,6 @@
1
+ class Float
2
+ # Converts number to a string with a format like xx,xxx,xxx.xxxx
3
+ def to_label()
4
+ BlackStack::Number::Encoding::format_with_separator(self)
5
+ end
6
+ end # class String
data/lib/functions.rb ADDED
@@ -0,0 +1,555 @@
1
+ module BlackStack
2
+ # -----------------------------------------------------------------------------------------
3
+ # DateTime Functions
4
+ # -----------------------------------------------------------------------------------------
5
+ module DateTime
6
+ # -----------------------------------------------------------------------------------------
7
+ # Encoding
8
+ # -----------------------------------------------------------------------------------------
9
+ module Encoding
10
+ # Convierte un objeto date-time a un string con formato sql-datetime (yyyy-mm-dd hh:mm:ss).
11
+ def self.datetime_to_sql(o)
12
+ return o.strftime("%Y-%m-%d %H:%M:%S")
13
+ end
14
+ end # module Encode
15
+
16
+ # -----------------------------------------------------------------------------------------
17
+ # Miscelaneous
18
+ # -----------------------------------------------------------------------------------------
19
+ module Misc
20
+ def self.datetime_values_check(year,month,day,hour,minute,second)
21
+ if (year.to_i<1900 || year.to_i>=2100)
22
+ return false
23
+ end
24
+
25
+ if (month.to_i<1 || month.to_i>12)
26
+ return false
27
+ end
28
+
29
+ # TODO: Considerar la cantidad de dias de cada mes, y los anios biciestos. Buscar alguna funcion existente.
30
+ if (day.to_i<1 || day.to_i>31)
31
+ return false
32
+ end
33
+
34
+ if (hour.to_i<0 || hour.to_i>23)
35
+ return false
36
+ end
37
+
38
+ if (minute.to_i<0 || minute.to_i>59)
39
+ return false
40
+ end
41
+
42
+ if (second.to_i<0 || second.to_i>59)
43
+ return false
44
+ end
45
+
46
+ return true
47
+ end # datetime_values_check
48
+ end # module Misc
49
+ end # module DateTime
50
+
51
+ # -----------------------------------------------------------------------------------------
52
+ # Numeric Functions
53
+ # -----------------------------------------------------------------------------------------
54
+ module Number
55
+ # -----------------------------------------------------------------------------------------
56
+ # Encoding
57
+ # -----------------------------------------------------------------------------------------
58
+ module Encoding
59
+ # Converts number to a string with a format like xx,xxx,xxx.xxxx
60
+ # number: it may be int or float
61
+ def self.format_with_separator(number)
62
+ whole_part, decimal_part = number.to_s.split('.')
63
+ [whole_part.gsub(/(\d)(?=\d{3}+$)/, '\1,'), decimal_part].compact.join('.')
64
+ end
65
+
66
+ # Convierte una cantidad de minutos a una leyenda legible por el usuario.
67
+ # Ejemplo: "2 days, 5 hours"
68
+ # Ejemplo: "4 hours, 30 minutes"
69
+ # Ejemplo: "3 days, 4 hour"
70
+ def self.encode_minutes(n)
71
+ # TODO: validar que n sea un entero mayor a 0
72
+ if (n<0)
73
+ return "?"
74
+ end
75
+ if (n<60)
76
+ return "#{n} minutes"
77
+ elsif (n<24*60)
78
+ return "#{(n/60).to_i} hours, #{n-60*(n/60).to_i} minutes"
79
+ else
80
+ return "#{(n/(24*60)).to_i} days, #{((n-24*60*(n/(24*60)).to_i)/60).to_i} hours"
81
+ end
82
+ end
83
+ end # module Encode
84
+ end # module Number
85
+
86
+ # -----------------------------------------------------------------------------------------
87
+ # String Functions
88
+ # -----------------------------------------------------------------------------------------
89
+ module Strings
90
+
91
+ GUID_SIZE = 36
92
+ MATCH_PASSWORD = /^(?=.*[a-zA-Z])(?=.*[0-9]).{6,}$/
93
+ MATCH_GUID = /[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]\-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]\-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]\-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]/
94
+ MATCH_FILENAME = /^[\w,\s-]+\.[A-Za-z]{3}$/
95
+ MATCH_EMAIL = /[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}/
96
+ MATCH_DOMAIN = /(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}/
97
+ MATCH_DATE_STANDARD = /^\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])$/
98
+ MATCH_PHONE = /(?:\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}/
99
+ MATCH_URL = /(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?/ # /(?:\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}/
100
+ MATCH_LINKEDIN_COMPANY_URL = /(https?:\/\/)?(www\\.)?linkedin\.com\/company\//
101
+ MATCH_FIXNUM = /^[0-9]+$/
102
+ MATCH_CONTENT_SPINNING = /{[^}]+}/
103
+ MATCH_SPINNED_TEXT = /code me/ # TODO: define this regex for the issue #1226
104
+
105
+ # -----------------------------------------------------------------------------------------
106
+ # Fuzzy String Comparsion Functions: How similar are 2 strings that are not exactly equal.
107
+ # -----------------------------------------------------------------------------------------
108
+ module SQL
109
+ def self.string_to_sql_string(s)
110
+ #return s.force_encoding("UTF-8").gsub("'", "''").to_s
111
+ return s.gsub("'", "''").to_s
112
+ end
113
+ end
114
+
115
+ # -----------------------------------------------------------------------------------------
116
+ # Fuzzy String Comparsion Functions: How similar are 2 strings that are not exactly equal.
117
+ # -----------------------------------------------------------------------------------------
118
+ module Comparing
119
+ # retorna 0 si los strings son iguales
120
+ # https://stackoverflow.com/questions/16323571/measure-the-distance-between-two-strings-with-ruby
121
+ def self.levenshtein_distance(s, t)
122
+ s.downcase!
123
+ t.downcase!
124
+
125
+ m = s.length
126
+ n = t.length
127
+ return m if n == 0
128
+ return n if m == 0
129
+ d = Array.new(m+1) {Array.new(n+1)}
130
+
131
+ (0..m).each {|i| d[i][0] = i}
132
+ (0..n).each {|j| d[0][j] = j}
133
+ (1..n).each do |j|
134
+ (1..m).each do |i|
135
+ d[i][j] = if s[i-1] == t[j-1] # adjust index into string
136
+ d[i-1][j-1] # no operation required
137
+ else
138
+ [ d[i-1][j]+1, # deletion
139
+ d[i][j-1]+1, # insertion
140
+ d[i-1][j-1]+1, # substitution
141
+ ].min
142
+ end
143
+ end
144
+ end
145
+ d[m][n]
146
+ end
147
+
148
+ # retorna la cantidad de palabras con mas de 3 caracteres que se encuentran en el parametro s
149
+ def self.max_sardi_distance(s)
150
+ s.downcase!
151
+ s.gsub!(/-/,' ')
152
+ ss = s.scan(/\b([a-z]+)\b/)
153
+ n = 0
154
+ ss.each { |x|
155
+ x = x[0]
156
+ if (x.size > 3) # para evitar keywords triviales como 'and'
157
+ n += 1
158
+ end
159
+ }
160
+ n
161
+ end
162
+
163
+ # retorna la cantidad de palabras con mas de 3 caracteres del parametro s que se encuentran en el parametro t
164
+ def self.sardi_distance(s, t)
165
+ s.downcase!
166
+ t.downcase!
167
+ s.gsub!(/-/,' ')
168
+ t.gsub!(/-/,' ')
169
+ max_distance = max_sardi_distance(s)
170
+ ss = s.scan(/\b([a-z]+)\b/)
171
+ tt = t.scan(/\b([a-z]+)\b/)
172
+ n = 0
173
+ ss.each { |x|
174
+ x = x[0]
175
+ if (x.size > 3) # para evitar keywords triviales como 'and'
176
+ if ( tt.select { |y| y[0] == x }.size > 0 )
177
+ n += 1
178
+ end
179
+ end
180
+ }
181
+ return max_distance - n
182
+ end
183
+ end # module Comparing
184
+
185
+ # -----------------------------------------------------------------------------------------
186
+ # Encoding: Make a string nice to be shown into an HTML string.
187
+ # -----------------------------------------------------------------------------------------
188
+ module Encoding
189
+ # Then it makes it compatible with UTF-8.
190
+ # More details here: https://bitbucket.org/leandro_sardi/blackstack/issues/961
191
+ def self.encode_string(s)
192
+ s.encode("UTF-8")
193
+ end
194
+
195
+ # Escape the string to be shown into an HTML screen.
196
+ # Then it makes it compatible with UTF-8.
197
+ # More details here: https://bitbucket.org/leandro_sardi/blackstack/issues/961
198
+ def self.encode_html(s)
199
+ encode_string(CGI.escapeHTML(s.to_s))
200
+ end
201
+
202
+ # Generates a description string from an exception object.
203
+ # Eescapes the string to be shown into an HTML screen.
204
+ # Makes it compatible with UTF-8.
205
+ # More details here: https://bitbucket.org/leandro_sardi/blackstack/issues/961
206
+ def self.encode_exception(e, include_backtrace=true)
207
+ ret = 'Error:' + encode_html(e.to_s)
208
+ if (include_backtrace == true)
209
+ e.backtrace.each { |s|
210
+ ret += "<br/>" + encode_html(s)
211
+ } # e.backtrace.each
212
+ end # if
213
+ ret
214
+ end
215
+
216
+ # Returns a string with a description of a period of time, to be shown in the screen.
217
+ # period: it may be 'H', 'D', 'W', 'M', 'Y'
218
+ # units: it is a positive integer
219
+ def self.encode_period(period, units)
220
+ s = "Last "
221
+ s += units.to_s + " " if units.to_i > 1
222
+ s += "Hours" if period.upcase == "H" && units.to_i != 1
223
+ s += "Days" if period.upcase == "D" && units.to_i != 1
224
+ s += "Weeks" if period.upcase == "W" && units.to_i != 1
225
+ s += "Months" if period.upcase == "M" && units.to_i != 1
226
+ s += "Years" if period.upcase == "Y" && units.to_i != 1
227
+ s += "Hour" if period.upcase == "H" && units.to_i == 1
228
+ s += "Day" if period.upcase == "D" && units.to_i == 1
229
+ s += "Week" if period.upcase == "W" && units.to_i == 1
230
+ s += "Month" if period.upcase == "M" && units.to_i == 1
231
+ s += "Year" if period.upcase == "Y" && units.to_i == 1
232
+ s
233
+ end
234
+
235
+ #
236
+ def self.encode_guid(s)
237
+ return s.gsub('{',"").gsub('}',"").upcase
238
+ end
239
+
240
+ #
241
+ def self.encode_javascript(s)
242
+ s.to_s.gsub("'", "\\\\'").gsub("\r", "' + String.fromCharCode(13) + '").gsub("\n", "' + String.fromCharCode(10) + '")
243
+ end
244
+
245
+ end # module Encoding
246
+
247
+ # -----------------------------------------------------------------------------------------
248
+ # DateTime
249
+ # -----------------------------------------------------------------------------------------
250
+ module DateTime
251
+ # Check the string has the format yyyymmddhhmmss.
252
+ # => Return true if success. Otherwise, return false.
253
+ # => Year cannot be lower than 1900.
254
+ # => Year cannot be higher or equal than 2100.
255
+ def self.datetime_api_check(s)
256
+ return false if (s.size!=14)
257
+ year = s[0..3]
258
+ month = s[4..5]
259
+ day = s[6..7]
260
+ hour = s[8..9]
261
+ minute = s[10..11]
262
+ second = s[12..13]
263
+ BlackStack::DateTime::Misc::datetime_values_check(year,month,day,hour,minute,second)
264
+ end # def datetime_api_check
265
+
266
+ # Check the string has the format yyyy-mm-dd hh:mm:ss.
267
+ # => Return true if success. Otherwise, return false.
268
+ # => Year cannot be lower than 1900.
269
+ # => Year cannot be higher or equal than 2100.
270
+ def self.datetime_sql_check(s)
271
+ return false if (s.size!=19)
272
+ year = s[0..3]
273
+ month = s[5..6]
274
+ day = s[8..9]
275
+ hour = s[11..12]
276
+ minute = s[14..15]
277
+ second = s[17..18]
278
+ BlackStack::DateTime::Misc::datetime_values_check(year,month,day,hour,minute,second)
279
+ end # def datetime_sql_check
280
+
281
+ # Convierte un string con formato api-datatime (yyyymmddhhmmss) a un string con formato sql-datetime (yyyy-mm-dd hh:mm:ss).
282
+ def self.datetime_api_to_sql(s)
283
+ raise "Wrong Api DataTime Format." if (datetime_api_check(s)==false)
284
+ year = s[0..3]
285
+ month = s[4..5]
286
+ day = s[6..7]
287
+ hour = s[8..9]
288
+ minute = s[10..11]
289
+ second = s[12..13]
290
+ ret = "#{year}-#{month}-#{day} #{hour}:#{minute}:#{second}"
291
+ return ret
292
+ end # def datetime_api_to_sql
293
+
294
+ # Convierte un string con formato sql-datatime a un string con formato sql-datetime.
295
+ def self.datetime_sql_to_api(s)
296
+ raise "Wrong SQL DataTime Format." if (datetime_sql_check(s)==false)
297
+ year = s[0..3]
298
+ month = s[5..6]
299
+ day = s[8..9]
300
+ hour = s[11..12]
301
+ minute = s[14..15]
302
+ second = s[17..18]
303
+ ret = "#{year}#{month}#{day}#{hour}#{minute}#{second}"
304
+ return ret
305
+ end # def datetime_sql_to_api
306
+ end # module DateTime
307
+
308
+
309
+ # -----------------------------------------------------------------------------------------
310
+ # Spinning
311
+ # -----------------------------------------------------------------------------------------
312
+ module Spinning
313
+ # Esta funcion retorna una variacion al azar del texto que se pasa.
314
+ # Esta funcion se ocupa de dividir el texto en partes, para eviar el error "too big to product" que arroja la libraría.
315
+ def self.random_spinning_variation(text)
316
+ ret = text
317
+
318
+ text.scan(MATCH_CONTENT_SPINNING).each { |s|
319
+ a = ContentSpinning.new(s).spin
320
+ rep = a[rand(a.size)]
321
+ ret = ret.gsub(s, rep)
322
+ a = nil
323
+ }
324
+
325
+ return ret
326
+ end
327
+
328
+ # retorna true si la sintaxis del texto spineado es correcta
329
+ # caso contrario retorna false
330
+ # no soporta spinnings anidados. ejemplo: {my|our|{a car of mine}}
331
+ def self.valid_spinning_syntax?(s)
332
+ # valido que exste
333
+ n = 0
334
+ s.split('').each { |c|
335
+ n+=1 if c=='{'
336
+ n-=1 if c=='}'
337
+ if n!=0 && n!=1
338
+ #raise "Closing spining char '}' with not previous opening spining char '{'." if n<0
339
+ #raise "Opening spining char '{' inside another spining block." if n>1
340
+ return false if n<0 # Closing spining char '}' with not previous opening spining char '{'.
341
+ return false if n>1 # Opening spining char '{' inside another spining block.
342
+ end
343
+ }
344
+
345
+ # obtengo cada uno de los spinnings
346
+ s.scan(MATCH_CONTENT_SPINNING).each { |x|
347
+ a = x.split('|')
348
+ raise "No variations delimited by '|' inside spinning block." if a.size <= 1
349
+ }
350
+
351
+ true
352
+ end
353
+
354
+ # returns true if the text is spinned.
355
+ # otherwise, returns false.
356
+ def self.spintax?(s)
357
+ s.scan(MATCH_CONTENT_SPINNING).size > 0
358
+ end
359
+ end # module Spinning
360
+
361
+
362
+ # -----------------------------------------------------------------------------------------
363
+ # Miscelaneus
364
+ # -----------------------------------------------------------------------------------------
365
+ module Misc
366
+ # make a Ruby string safe for a filesystem.
367
+ # References:
368
+ # => https://stackoverflow.com/questions/1939333/how-to-make-a-ruby-string-safe-for-a-filesystem
369
+ # => http://devblog.muziboo.com/2008/06/17/attachment-fu-sanitize-filename-regex-and-unicode-gotcha/
370
+ def self.sanitize_filename(filename)
371
+ ret = filename.strip do |name|
372
+ # NOTE: File.basename doesn't work right with Windows paths on Unix
373
+ # get only the filename, not the whole path
374
+ name.gsub!(/^.*(\\|\/)/, '')
375
+
376
+ # Strip out the non-ascii character
377
+ name.gsub!(/[^0-9A-Za-z.\-]/, '_')
378
+ end
379
+ return ret
380
+ end
381
+ end # module Misc
382
+
383
+
384
+ # -----------------------------------------------------------------------------------------
385
+ # Email Appending Functions
386
+ # -----------------------------------------------------------------------------------------
387
+ module Appending
388
+ APPEND_PATTERN_FNAME_DOT_LNAME = 0
389
+ APPEND_PATTERN_FNAME = 1
390
+ APPEND_PATTERN_LNAME = 2
391
+ APPEND_PATTERN_F_LNAME = 3
392
+ APPEND_PATTERN_F_DOT_LNAME = 4
393
+
394
+ #
395
+ def self.name_pattern(pattern, fname, lname)
396
+ if (pattern==APPEND_PATTERN_FNAME_DOT_LNAME)
397
+ return "#{fname}.#{lname}"
398
+ elsif (pattern==APPEND_PATTERN_FNAME)
399
+ return "#{fname}"
400
+ elsif (pattern==APPEND_PATTERN_LNAME)
401
+ return "#{lname}"
402
+ elsif (pattern==APPEND_PATTERN_F_LNAME)
403
+ return "#{fname[0]}#{lname}"
404
+ elsif (pattern==APPEND_PATTERN_F_DOT_LNAME)
405
+ return "#{fname[0]}.#{lname}"
406
+ else
407
+ raise "getNamePattern: Unknown pattern code."
408
+ end
409
+ end
410
+
411
+ #
412
+ def self.get_email_variations(first_name, last_name, domain, is_a_big_company)
413
+ variations = Array.new
414
+ variations << first_name + "." + last_name + "@" + domain
415
+ variations << first_name[0] + last_name + "@" + domain
416
+ variations << first_name + "_" + last_name + "@" + domain
417
+ variations << first_name[0] + "." + last_name + "@" + domain
418
+ if (is_a_big_company == false)
419
+ variations << last_name + "@" + domain
420
+ variations << first_name + "@" + domain
421
+ end
422
+ #variations << first_name + "." + last_name + "@" + domain
423
+ #variations << first_name + "_" + last_name + "@" + domain
424
+ #variations << last_name + "." + first_name + "@" + domain
425
+ #variations << last_name + "_" + first_name + "@" + domain
426
+ #variations << first_name[0] + "." + last_name + "@" + domain
427
+ #variations << first_name + "." + last_name[0] + "@" + domain
428
+ #variations << last_name[0] + "." + first_name + "@" + domain
429
+ #variations << last_name + "." + first_name[0] + "@" + domain
430
+ #variations << first_name[0] + last_name + "@" + domain
431
+ #variations << first_name + last_name[0] + "@" + domain
432
+ #variations << last_name[0] + first_name + "@" + domain
433
+ #variations << last_name + first_name[0] + "@" + domain
434
+ #variations << first_name + "@" + domain
435
+ #variations << last_name + "@" + domain
436
+ return variations
437
+ end
438
+ end # module Appending
439
+ end # module String
440
+
441
+ # -----------------------------------------------------------------------------------------
442
+ # Network
443
+ # -----------------------------------------------------------------------------------------
444
+ module Netting
445
+ CALL_METHOD_GET = 'get'
446
+ CALL_METHOD_POST = 'post'
447
+ DEFAULT_SSL_VERIFY_MODE = OpenSSL::SSL::VERIFY_NONE
448
+ SUCCESS = 'success'
449
+
450
+ # New call_get
451
+ def self.call_get(uri, params = {}, ssl_verify_mode=BlackStack::Netting::DEFAULT_SSL_VERIFY_MODE)
452
+ uri.query = URI.encode_www_form(params)
453
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https', :verify_mode => ssl_verify_mode) do |http|
454
+ req = Net::HTTP::Get.new uri
455
+ res = http.request req
456
+ case res
457
+ when Net::HTTPSuccess then res
458
+ when Net::HTTPRedirection then BlackStack::Netting::call_get(URI(res['location']), params)
459
+ else
460
+ res.error!
461
+ end
462
+ end
463
+ end
464
+
465
+ # New call_post
466
+ def self.call_post(uri, params = {}, ssl_verify_mode=BlackStack::Netting::DEFAULT_SSL_VERIFY_MODE)
467
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https', :verify_mode => ssl_verify_mode) do |http|
468
+ req = Net::HTTP::Post.new(uri)
469
+ req['Content-Type'] = 'application/json'
470
+ req.set_form_data(params)
471
+ res = http.request req
472
+ case res
473
+ when Net::HTTPSuccess then res
474
+ when Net::HTTPRedirection then BlackStack::Netting::call_post(URI(res['location']), params)
475
+ else
476
+ res.error!
477
+ end
478
+ end
479
+ end
480
+
481
+ #
482
+ def self.api_call(url, params={}, method=BlackStack::Netting::CALL_METHOD_POST, ssl_verify_mode=BlackStack::Netting::DEFAULT_SSL_VERIFY_MODE, max_retries=5)
483
+ nTries = 0
484
+ bSuccess = false
485
+ parsed = nil
486
+ sError = ""
487
+ while (nTries < max_retries && bSuccess == false)
488
+ begin
489
+ nTries = nTries + 1
490
+ uri = URI(url)
491
+ res = BlackStack::Netting::call_post(uri, params, ssl_verify_mode) if method==BlackStack::Netting::CALL_METHOD_POST
492
+ res = BlackStack::Netting::call_get(uri, params, ssl_verify_mode) if method==BlackStack::Netting::CALL_METHOD_GET
493
+ parsed = JSON.parse(res.body)
494
+ if (parsed['status']==BlackStack::Netting::SUCCESS)
495
+ bSuccess = true
496
+ else
497
+ sError = "Status: #{parsed['status'].to_s}. Description: #{parsed['value'].to_s}."
498
+ end
499
+ rescue Errno::ECONNREFUSED => e
500
+ sError = "Errno::ECONNREFUSED:" + e.to_s
501
+ rescue => e2
502
+ sError = "Exception:" + e2.to_s
503
+ end
504
+ end # while
505
+
506
+ if (bSuccess==false)
507
+ raise "#{sError}"
508
+ end
509
+ end # apicall
510
+
511
+ # Download a file from an url to a local folder.
512
+ # url: must be somedomain.net instead of somedomain.net/, otherwise, it will throw exception.
513
+ # to: must be a valid path to a folder.
514
+ def self.download(url, to)
515
+ uri = URI(url)
516
+ domain = uri.host.start_with?('www.') ? uri.host[4..-1] : uri.host
517
+ path = uri.path
518
+ filename = path.split("/").last
519
+ Net::HTTP.start(domain) do |http|
520
+ resp = http.get(path)
521
+ open(to, "wb") do |file|
522
+ file.write(resp.body)
523
+ end
524
+ end
525
+ end
526
+
527
+ # Return the extension of the last path into an URL.
528
+ # Example: get_url_extension("http://connect.data.com/sitemap_index.xml?foo_param=foo_value") => ".xml"
529
+ def self.get_url_extension(url)
530
+ return File.extname(URI.parse(url).path.to_s)
531
+ end
532
+
533
+ # Removes the 'www.' from an URL.
534
+ def self.get_host_without_www(url)
535
+ url = "http://#{url}" if URI.parse(url).scheme.nil?
536
+ host = URI.parse(url).host.downcase
537
+ host.start_with?('www.') ? host[4..-1] : host
538
+ end
539
+
540
+ # Get the final URL if a web page is redirecting.
541
+ def self.get_redirect(url)
542
+ uri = URI.parse(url)
543
+ protocol = uri.scheme
544
+ host = uri.host.downcase
545
+ res = Net::HTTP.get_response(uri)
546
+ "#{protocol}://#{host}#{res['location']}"
547
+ end
548
+
549
+ # returns the age in days of the given file
550
+ def self.file_age(filename)
551
+ (Time.now - File.ctime(filename))/(24*3600)
552
+ end
553
+ end # module Netting
554
+
555
+ end # module BlackStack
data/lib/string.rb ADDED
@@ -0,0 +1,115 @@
1
+ class String
2
+ # returns true if the string meets all the security requirements for a password
3
+ def password?
4
+ return true if self.to_s =~ BlackStack::Strings::MATCH_PASSWORD
5
+ return false
6
+ end
7
+
8
+ # returns true if the string match with the regex of a GUID
9
+ def guid?
10
+ return true if self.to_s =~ BlackStack::Strings::MATCH_GUID
11
+ return false
12
+ end
13
+
14
+ # returns true if the string match with the regex of a filename
15
+ def filename?
16
+ return true if self.to_s =~ BlackStack::Strings::MATCH_FILENAME
17
+ return false
18
+ end
19
+
20
+ # returns true if the string match with the regex of an email
21
+ def email?
22
+ return true if self.to_s =~ BlackStack::Strings::MATCH_EMAIL
23
+ return false
24
+ end
25
+
26
+ # returns true if the string match with the regex of a domain
27
+ def domain?
28
+ return true if self.to_s =~ BlackStack::Strings::MATCH_DOMAIN
29
+ return false
30
+ end
31
+
32
+ # returns true if the string match with the regex of a phone number
33
+ def phone?
34
+ return true if self.to_s =~ BlackStack::Strings::MATCH_PHONE
35
+ return false
36
+ end
37
+
38
+ # returns true if the string match with the regex of a URL
39
+ def url?
40
+ return true if self.to_s =~ BlackStack::Strings::MATCH_URL
41
+ return false
42
+ end
43
+
44
+ # returns true if the string match with the regex of a number
45
+ def fixnum?
46
+ return true if self.to_s =~ BlackStack::Strings::MATCH_FIXNUM
47
+ return false
48
+ end
49
+
50
+ # returns true if the string match with the regex of a datetime used in the BlackStack's API
51
+ def api_datetime?
52
+ BlackStack::Strings::DateTime::datetime_api_check(self.to_s)
53
+ end
54
+
55
+ #
56
+ def sql_datetime?
57
+ BlackStack::Strings::DateTime::datetime_sql_check(self.to_s)
58
+ end
59
+
60
+ # Convierte un string con formato sql-datatime a un string con formato sql-datetime.
61
+ def sql_to_api_datetime
62
+ BlackStack::Strings::DateTime::datetime_sql_to_api(self.to_s)
63
+ end
64
+
65
+ # Convierte un string con formato api-datatime (yyyymmddhhmmss) a un string con formato sql-datetime (yyyy-mm-dd hh:mm:ss).
66
+ def api_to_sql_datetime
67
+ BlackStack::Strings::DateTime::datetime_api_to_sql(self.to_s)
68
+ end
69
+
70
+ # Rewrite a GUID as a standard format.
71
+ # Example: {331a92c3-5fe1-47a2-a31b-cfa439b5b4f9} -> 331A92C3-5FE1-47A2-A31B-CFA439B5B4F9
72
+ def to_guid
73
+ BlackStack::Strings::Encoding::encode_guid(self.to_s)
74
+ end
75
+
76
+ # Escape simple-quotes too add the string into literal-string of a dynamic query build into the Ruby code.
77
+ # Example: "I'm BlackStack" -> "I''m BlackStack"
78
+ def to_sql
79
+ BlackStack::Strings::SQL::string_to_sql_string(self.to_s)
80
+ end
81
+
82
+ #
83
+ def spintax?
84
+ BlackStack::Strings::Spinning::spintax?(self.to_s)
85
+ end
86
+
87
+ #
88
+ def spintax?
89
+ BlackStack::Strings::Spinning::valid_spinning_syntax?(self.to_s) &&
90
+ BlackStack::Strings::Spinning::spintax?(self.to_s)
91
+ end
92
+
93
+ # Returns a random spin from a spintax
94
+ def spin
95
+ BlackStack::Strings::Spinning::random_spinning_variation(self.to_s)
96
+ end
97
+
98
+ # Then it makes it compatible with UTF-8.
99
+ # More details here: https://bitbucket.org/leandro_sardi/blackstack/issues/961
100
+ def encode_string()
101
+ BlackStack::Strings::Encoding::encode_string(self.to_s)
102
+ end
103
+
104
+ # Escape the string to be shown into an HTML screen.
105
+ # Then it makes it compatible with UTF-8.
106
+ # More details here: https://bitbucket.org/leandro_sardi/blackstack/issues/961
107
+ def encode_html()
108
+ BlackStack::Strings::Encoding::encode_html(self.to_s)
109
+ end
110
+
111
+ end # class String
112
+
113
+ #i.to_label
114
+
115
+ #dt.to_sql
data/lib/time.rb ADDED
@@ -0,0 +1,6 @@
1
+ class Time
2
+ # Converts a time object to an SQL friendy string
3
+ def to_sql()
4
+ BlackStack::DateTime::Encoding::datetime_to_sql(self)
5
+ end
6
+ end # class DateTime
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blackstack_commons
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leandro Daniel Sardi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-06 00:00:00.000000000 Z
11
+ date: 2019-11-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: content_spinning
@@ -56,7 +56,16 @@ executables: []
56
56
  extensions: []
57
57
  extra_rdoc_files: []
58
58
  files:
59
+ - examples/example01.rb
60
+ - examples/example02.rb
59
61
  - lib/blackstack_commons.rb
62
+ - lib/datetime.rb
63
+ - lib/exception.rb
64
+ - lib/fixnum.rb
65
+ - lib/float.rb
66
+ - lib/functions.rb
67
+ - lib/string.rb
68
+ - lib/time.rb
60
69
  homepage: https://rubygems.org/gems/blackstack_commons
61
70
  licenses:
62
71
  - MIT