pad_utils 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f6939b46b2b13a5954d87a24eebe598fd044e4af
4
+ data.tar.gz: 4d803c5b1fac23443d42b84e15a4e4b0e14d2dc3
5
+ SHA512:
6
+ metadata.gz: 2f759bb5c6e0e96b5ce794df6301cf3cb3bd2002451a652680a799e1e4e48a5eda6081c328fdf78d5803dc3eef9979e3375ad24bd748f4c9bdfad1d78983c0b4
7
+ data.tar.gz: 64ef8ed6c014074b66c5eb63fc55cec26f2706e1c41aad78cc384ad9ebedb320319e30af515fa39a3fac627ea93a04b934238bd8676df4ef39725e04cfa0eb0f
data/LICENSE.txt ADDED
@@ -0,0 +1,177 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
data/README.md ADDED
@@ -0,0 +1,269 @@
1
+ # PadUtils
2
+
3
+ PadUtils is a simple gem containing common utilities and shortcuts. It is used in the [Padstone](http://padstone.io) app builder but can be embedded in any other Ruby project.
4
+
5
+ ## Installation
6
+
7
+ It's a Ruby gem. Install it like any other gem!
8
+
9
+ `gem install pad_utils`
10
+
11
+ ## Usage
12
+
13
+ Just `require 'pad_utils'` within your code to access the following methods.
14
+
15
+ ### Build CLI menus
16
+
17
+ #### 1. Yes/No menu
18
+
19
+ Prompt user with a cli yes/no menu. Returns `true` or `false`.
20
+
21
+ * `question`: the question to ask
22
+ * `default`: the default answer
23
+
24
+ `PadUtils.yes_no_menu(question: "Question?", default: "y")`
25
+
26
+ #### 2. Open question menu
27
+
28
+ Prompt user with a cli open question menu. Returns a `string`.
29
+
30
+ `PadUtils.question_menu(question)`
31
+
32
+ #### 3. Multiple choice menu
33
+
34
+ Prompt user with a multiple choice menu. Returns a `symbol`.
35
+
36
+ * `question`: the question to ask
37
+ * `choices`: hash of choices (e.g. `{b: "blue", r: "red"}`)
38
+ * `default`: symbol representing the default value. If none provided, last value in choices hash will be used.
39
+
40
+ `PadUtils.choice_menu(question: "Question?", choices: {}, default: nil)`
41
+
42
+
43
+ ### Work with text
44
+
45
+ #### 1. Convert a string to a Rubified name
46
+
47
+ Convert a string into a proper "rubified" name. For example, 'app_name' will be converted to 'AppName'. Returns a `string`.
48
+
49
+ `PadUtils.convert_to_ruby_name(value)`
50
+
51
+ #### 2. Sanitize a string
52
+
53
+ Sanitize a string by replacing special characters (including spaces) with underscores. Returns a `string`.
54
+
55
+ `PadUtils.sanitize(value)`
56
+
57
+ #### 3. Replace a string in a file
58
+
59
+ Replace text within a file. `old_text` can either be a `string` or a `regex`. Doesn't return anything, overwrites `file`.
60
+
61
+ `PadUtils.replace_in_file(file, old_text, new_text)`
62
+
63
+ #### 4. Insert text before first occurence
64
+
65
+ Insert text in a string or a file before the first occurence of a string. Returns a `string`. If `is_file` is `true`, overwrites `original` file.
66
+
67
+ * `original`: the original string or filename
68
+ * `tag`: occurence of string to find
69
+ * `text`: string to insert
70
+ * `is_file`: `true` if `original` is a filename (default), `false` if it's a `string`
71
+
72
+ `PadUtils.insert_before_first(original: nil, tag: nil, text: nil, is_file: true)`
73
+
74
+ #### 5. Insert text before last occurence
75
+
76
+ Insert text in a string or a file before the last occurence of a string. Returns a `string`. If `is_file` is `true`, overwrites `original` file.
77
+
78
+ * `original`: the original string or filename
79
+ * `tag`: occurence of string to find
80
+ * `text`: string to insert
81
+ * `is_file`: `true` if `original` is a filename (default), `false` if it's a `string`
82
+
83
+ `PadUtils.insert_before_last(original: nil, tag: nil, text: nil, is_file: true)`
84
+
85
+ #### 6. Insert text after first occurence
86
+
87
+ Insert text in a string or a file after the first occurence of a string. Returns a `string`. If `is_file` is `true`, overwrites `original` file.
88
+
89
+ * `original`: the original string or filename
90
+ * `tag`: occurence of string to find
91
+ * `text`: string to insert
92
+ * `is_file`: `true` if `original` is a filename (default), `false` if it's a `string`
93
+
94
+ `PadUtils.insert_after_first(original: nil, tag: nil, text: nil, is_file: true)`
95
+
96
+ #### 7. Insert text after last occurence
97
+
98
+ Insert text in a string or a file after the last occurence of a string. Returns a `string`. If `is_file` is `true`, overwrites `original` file.
99
+
100
+ * `original`: the original string or filename
101
+ * `tag`: occurence of string to find
102
+ * `text`: string to insert
103
+ * `is_file`: `true` if `original` is a filename (default), `false` if it's a `string`
104
+
105
+ `PadUtils.insert_after_last(original: nil, tag: nil, text: nil, is_file: true)`
106
+
107
+ ### JSON and Hash
108
+
109
+ Few methods to convert JSON to deep symbolized hash and back.
110
+
111
+ #### 1. Symbolize all keys in a hash
112
+
113
+ Convert all keys and sub-keys to symbols in a hash. Emulates the `deep_symbolize_keys` found in [Rails](http://apidock.com/rails/Hash/deep_symbolize_keys). Returns a `Hash`.
114
+
115
+ `PadUtils.deep_symbolize_hash_keys(hash)`
116
+
117
+ #### 2. Convert a JSON string to a symbolized hash
118
+
119
+ Returns a `Hash`.
120
+
121
+ `PadUtils.json_to_hash(json)`
122
+
123
+ #### 3. Load a JSON file and convert it to a symbolized hash
124
+
125
+ Returns a `Hash`.
126
+
127
+ `PadUtils.json_file_to_hash(json_filename)`
128
+
129
+ #### 4. Convert a hash to JSON
130
+
131
+ *Alias method on `to_json` for consistency.*
132
+
133
+ Returns a `string`.
134
+
135
+ `PadUtils.hash_to_json(hash)`
136
+
137
+ #### 5. Write a hash to a JSON file
138
+
139
+ Returns the file content as a `string`.
140
+
141
+ `PadUtils..hash_to_json_file(filename, hash)`
142
+
143
+ ### Work with files
144
+
145
+ Mostly, these are convenience methods aliasing existing Ruby methods. Implemented for consistency.
146
+
147
+ #### 1. Delete a file
148
+
149
+ Delete a file. If not found, doesn't raise any error.
150
+
151
+ `delete_file(file_path)`
152
+
153
+ #### 2. Does a file exist?
154
+
155
+ Returns `true` or `false`.
156
+
157
+ `PadUtils.file_exist?(file_path)`
158
+
159
+ #### 3. Copy a file
160
+
161
+ **Will override file if it already exists!**
162
+
163
+ `PadUtils.copy_file(file_path, dest_dir)`
164
+
165
+ #### 4. Move a file
166
+
167
+ **Will not throw an error if original file doesn't exist!**
168
+
169
+ `PadUtils.move_file(file_path, dest_file)`
170
+
171
+ #### 5. Copy multiple files
172
+
173
+ `PadUtils.copy_files(files_array, dest_dir)`
174
+
175
+ #### 6. Copy all files
176
+
177
+ Copy all files from a directory to another. *Will create destination if it doesn't exist*.
178
+
179
+ `PadUtils.copy_all_files(source_dir, dest_dir)`
180
+
181
+ #### 7. Create a directory
182
+
183
+ Create a directory and subdirectories. **Won't complain if it already exists. Won't override content**.
184
+
185
+ `PadUtils.create_directory(dir_name)`
186
+
187
+ #### 8. Delete a directory and its content
188
+
189
+ `PadUtils.delete_directory(dir_name)`
190
+
191
+ #### 9. Read content of a file
192
+
193
+ Returns a `string`.
194
+
195
+ `PadUtils.get_file_content(filepath)`
196
+
197
+ #### 10. Write to a file
198
+
199
+ Write content to a file. Create it if it doesn't exist. **Overwrites it if it already exists!**.
200
+
201
+ `PadUtils.write_to_file(filepath, content)`
202
+
203
+ #### 11. Append to a file
204
+
205
+ Append content to the end of a file. Create it if it doesn't exist.
206
+
207
+ **It will write a newline character first. If you don't want that,
208
+ set the `new_line` option to `false`**.
209
+
210
+ `PadUtils.append_to_file(filepath, content, new_line = true)`
211
+
212
+ ### Logging
213
+
214
+ By default, logs will go to `~/pad_logs/logs.txt`.
215
+
216
+ * Change default path: `PadUtils.log_path = "/new/path/to/logs"`
217
+ * Change default file name: `PadUtils.log_file = "my_logs.txt"`
218
+
219
+ To log a message, you call `log` and pass it a `message` string. Optionally, you can also pass an `Exception` object in the parameters:
220
+
221
+ `PadUtils.log(message, e = nil)`
222
+
223
+ ### Some time methods
224
+
225
+ #### 1. Time to string timestamp
226
+
227
+ Returns a `string` timestamp with the format `YYYYMMDDHHmmss` from a `Time` object.
228
+
229
+ `PadUtils.time_to_stamp(val)`
230
+
231
+ #### 2. String to time
232
+
233
+ Returns a `Time` object from a timestamp with the format `YYYYMMDDHHmmss`
234
+
235
+ `PadUtils.stamp_to_time(val)`
236
+
237
+ #### 3. Time to readable string
238
+
239
+ Returns a `string` readable timestamp with format `YYYY-MM-DD HH:mm:ss` from a `Time` object.
240
+
241
+ `PadUtils.time_to_readable_stamp(val)`
242
+
243
+ #### 4. Readable timestamp to time
244
+
245
+ Returns a `Time` object from a readable timestamp `string` with format `YYYY-MM-DD HH:mm:ss`
246
+
247
+ `PadUtils.readable_stamp_to_time(val)`
248
+
249
+ ## Contribute
250
+
251
+ [Get in touch](https://twitter.com/nicoschuele) before submitting a pull request, I don't want to waste your time by rejecting it!
252
+
253
+ ## Testing
254
+
255
+ The test suite for PadUtils is currently outside of the gem itself. I may add it if I have time.
256
+
257
+ ## License
258
+
259
+ Copyright 2016 - Nico Schuele
260
+
261
+ Licensed under the Apache License, Version 2.0 (the "License");
262
+ you may not use this file except in compliance with the License.
263
+ You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
264
+
265
+ Unless required by applicable law or agreed to in writing, software
266
+ distributed under the License is distributed on an "AS IS" BASIS,
267
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
268
+ See the License for the specific language governing permissions and
269
+ limitations under the License.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :spec
data/bin/padutils ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/pad_utils"
4
+
5
+ PadUtils::main ARGV
@@ -0,0 +1,80 @@
1
+ require "fileutils"
2
+
3
+ module PadUtils
4
+
5
+ # The following methods are just here for convenience and consistency.
6
+ # Most are wrappers on FileUtils existing methods. Having them here,
7
+ # a user of PadUtils doesn't have to remember names and parameters.
8
+
9
+ # Delete a file. If not found, doesn't raise any error.
10
+ def self.delete_file(file_path)
11
+ FileUtils.rm(file_path, force: true)
12
+ end
13
+
14
+ # Just a wrapper on File.exist? for consistency.
15
+ def self.file_exist?(file_path)
16
+ File.exist?(file_path)
17
+ end
18
+
19
+ # Just a wrapper on FileUtils.cp for consistency.
20
+ # Will override file if it already exists!
21
+ def self.copy_file(file_path, dest_dir)
22
+ FileUtils.cp(file_path, dest_dir)
23
+ end
24
+
25
+ # Just a wrapper on FileUtils.mv for consistency.
26
+ # Will not throw an error if original file doesn't exist
27
+ def self.move_file(file_path, dest_file)
28
+ FileUtils.mv(file_path, dest_file, force: true)
29
+ end
30
+
31
+ # Copy an array of files
32
+ def self.copy_files(files, dest_dir)
33
+ files.each do |f|
34
+ copy_file(f, dest_dir)
35
+ end
36
+ end
37
+
38
+ # Copy all files from a directory to another.
39
+ # Will create destination if it doesn't exist
40
+ def self.copy_all_files(orig_dir, dest_dir)
41
+ FileUtils.copy_entry(orig_dir, dest_dir)
42
+ end
43
+
44
+ # Create a directory and subdirectories
45
+ # Won't complain if it already exists. Won't override content.
46
+ def self.create_directory(dir_name)
47
+ FileUtils.mkdir_p(dir_name)
48
+ end
49
+
50
+ # Delete a directory and its content.
51
+ # Just a wrapper for consistency.
52
+ def self.delete_directory(dir_name)
53
+ FileUtils.rm_r(dir_name)
54
+ end
55
+
56
+ # Reads content of a file. Method created for consistency.
57
+ def self.get_file_content(filepath)
58
+ File.read(filepath)
59
+ rescue Exception => e
60
+ PadUtils.log("Error in get_file_content", e)
61
+ end
62
+
63
+ # Write content to a file. Create it if it doesn't exist.
64
+ def self.write_to_file(filepath, content)
65
+ File.open(filepath, 'w') { |f| f.write(content)}
66
+ rescue Exception => e
67
+ PadUtils.log("Error in write_to_file", e)
68
+ end
69
+
70
+ # Append content to the end of a file. Create it if it doesn't exist.
71
+ # It will write a newline character first. If you don't want that,
72
+ # set the new_line option to false.
73
+ def self.append_to_file(filepath, content, new_line = true)
74
+ content = "\n#{content}" if new_line
75
+ File.open(filepath, 'a') { |f| f.write("#{content}")}
76
+ rescue Exception => e
77
+ PadUtils.log("Error in append_to_file", e)
78
+ end
79
+
80
+ end
@@ -0,0 +1,44 @@
1
+ require 'json'
2
+
3
+ module PadUtils
4
+
5
+ # Convert all keys and sub-keys to symbols in a hash.
6
+ # Emulates the deep_symbolize_keys found in Rails.
7
+ # Returns a Hash.
8
+ def self.deep_symbolize_hash_keys(hash)
9
+ return hash.collect { |e| deep_symbolize_hash_keys(e) } if hash.is_a?(Array)
10
+ return hash.inject({}) { |sh,(k,v)| sh[k.to_sym] = deep_symbolize_hash_keys(v); sh } if hash.is_a?(Hash)
11
+ hash
12
+ end
13
+
14
+ # Convert a JSON string to a symbolized hash.
15
+ # Returns a hash.
16
+ def self.json_to_hash(json)
17
+ h = JSON.parse(json)
18
+ self.deep_symbolize_hash_keys(h)
19
+ end
20
+
21
+ # Load a JSON file and convert it to a symbolized hash.
22
+ # Returns a hash.
23
+ def self.json_file_to_hash(json_file)
24
+ jfile = PadUtils.get_file_content(json_file)
25
+ h = JSON.parse(jfile)
26
+ self.deep_symbolize_hash_keys(h)
27
+ end
28
+
29
+ # Convert a hash to JSON. Alias method for consistency.
30
+ # Returns a string
31
+ def self.hash_to_json(hash)
32
+ hash.to_json
33
+ end
34
+
35
+ # Write a hash to a json file.
36
+ # Returns the file content as a string.
37
+ def self.hash_to_json_file(filename, hash)
38
+ json = hash.to_json
39
+ PadUtils.write_to_file(filename, json)
40
+ json
41
+ end
42
+
43
+
44
+ end
@@ -0,0 +1,44 @@
1
+ module PadUtils
2
+
3
+ # Module variable holding the log path. By default,
4
+ # logs will go in ~/pad_logs/
5
+ @@log_path = "#{ENV["HOME"]}/pad_logs"
6
+
7
+ # Module variable holding the log file. By default,
8
+ # logs will go in @@log_path/logs.txt
9
+ @@log_file = "logs.txt"
10
+
11
+ # Set another log path
12
+ def self.set_log_path(val)
13
+ @@log_path = val
14
+ end
15
+
16
+ # Set another log file
17
+ def self.set_log_file(val)
18
+ @@log_file = val
19
+ end
20
+
21
+ # Log a message
22
+ def self.log(message, e = nil)
23
+ # Create the log directory if it doesn't exist
24
+ PadUtils.create_directory(@@log_path)
25
+
26
+ # Add a timestamp to the message
27
+ message = "#{PadUtils.time_to_stamp(Time.now)}: #{message}"
28
+
29
+ # If an error is added, add its inner message to the message
30
+ # as well as the whole stack
31
+ if e != nil
32
+ message = "#{message}\n\tError: #{e.message} (#{e.class.name})"
33
+ stack = e.backtrace.inspect.split(",")
34
+ stack.each do |s|
35
+ message = "#{message}\n\t\t#{s}"
36
+ end
37
+ message = "#{message}\n"
38
+ end
39
+
40
+ # Adds the message to the log file
41
+ PadUtils.append_to_file("#{@@log_path}/#{@@log_file}", message)
42
+ end
43
+
44
+ end
@@ -0,0 +1,55 @@
1
+ module PadUtils
2
+
3
+ # Prompt user with a cli yes/no menu. Returns true or false.
4
+ # question: the question to ask
5
+ # default: the default answer
6
+ def self.yes_no_menu(question: "Question?", default: "y")
7
+ default_answer = default == "y" ? "(Y/n)" : "(y/N)"
8
+ STDOUT.print "#{question} #{default_answer}: "
9
+ answer = STDIN.gets.chomp.strip.downcase
10
+ answer = default if answer.length < 1
11
+ answer == "y"
12
+
13
+ rescue Exception => e
14
+ PadUtils.log("Error in yes/no menu", e)
15
+ end
16
+
17
+ # Prompt user with a cli open question menu. Returns a string.
18
+ def self.question_menu(question)
19
+ STDOUT.print "#{question}: "
20
+ STDIN.gets.chomp.strip
21
+ end
22
+
23
+ # Prompt user with a multiple choice menu. Returns a symbol. Always!
24
+ # question: the question to ask
25
+ # choices: hash of choices (e.g. {b: "blue", r: "red"})
26
+ # default: symbol representing the default value. If none provided, last
27
+ # value in choices hash will be used.
28
+ def self.choice_menu(question: "Question?", choices: {}, default: nil)
29
+ STDOUT.puts
30
+ STDOUT.puts "- #{question}"
31
+ default ||= choices.keys.last
32
+ default = default.to_sym
33
+
34
+ i = 0
35
+ choices.each do |key, value|
36
+ i += 1
37
+ STDOUT.print "#{i}. #{value}"
38
+ STDOUT.print " (default)" if key.to_s == default.to_s
39
+ STDOUT.print "\n"
40
+ end
41
+
42
+ STDOUT.print "Your choice (1-#{choices.length}): "
43
+ answer = STDIN.gets.chomp.strip.to_i
44
+ STDOUT.puts
45
+ if answer == 0 || answer > choices.length
46
+ return default
47
+ else
48
+ return choices.keys[answer - 1].to_sym
49
+ end
50
+
51
+ rescue Exception => e
52
+ PadUtils.log("Error in choice menu", e)
53
+ end
54
+
55
+ end
@@ -0,0 +1,181 @@
1
+ module PadUtils
2
+
3
+ # Convert a string into a proper Ruby name.
4
+ # For example, 'app_name' will be converted to 'AppName'
5
+ def self.convert_to_ruby_name(value)
6
+ if value.scan(/\_|\-/).size > 0
7
+ value.split(/\_|\-/).map(&:capitalize).join
8
+ else
9
+ value.slice(0,1).capitalize + value.slice(1..-1)
10
+ end
11
+ end
12
+
13
+ # Convert a string to only alphanumeric and underscores
14
+ def self.sanitize(value)
15
+ value.tr('^A-Za-z0-9', '_')
16
+ end
17
+
18
+ # Replace text within a file.
19
+ # old_text can be a regex or a string
20
+ def self.replace_in_file(file, old_text, new_text)
21
+ text_update = PadUtils.get_file_content(file)
22
+ text_update = text_update.gsub(old_text, new_text)
23
+
24
+ PadUtils.write_to_file(file, text_update)
25
+ rescue Exception => e
26
+ PadUtils.log("Error replacing #{old_text} in #{file} with #{new_text}", e)
27
+ end
28
+
29
+ # Insert text in a string or a file before the first occurence of a string.
30
+ # original: the original string or filename
31
+ # tag: occurence of string to find
32
+ # text: string to insert
33
+ # is_file: say if original is a file (default: true) or a string
34
+ def self.insert_before_first(original: nil, tag: nil, text: nil, is_file: true)
35
+ # The new text will be consolidated in content
36
+ content = ""
37
+
38
+ # If coming from a file, read original into content
39
+ if is_file
40
+ content = PadUtils.get_file_content(original)
41
+ else
42
+ content = original
43
+ end
44
+
45
+ # Iterate line by line. If a position is found, insert the text
46
+ # and set found to true to prevent further insertions
47
+ found = false
48
+ new_content = ""
49
+ content.each_line do |line|
50
+ position = line.index(/#{tag}/)
51
+ if position && !found
52
+ new_content += "#{text}#{line}"
53
+ found = true
54
+ else
55
+ new_content += line
56
+ end
57
+ end
58
+
59
+ # If coming from a file, write result in same file. If not,
60
+ # simply return content
61
+ if is_file
62
+ PadUtils.write_to_file(original, new_content)
63
+ return new_content
64
+ else
65
+ return new_content
66
+ end
67
+
68
+ rescue Exception => e
69
+ PadUtils.log("Error in insert_before_first", e)
70
+ end
71
+
72
+ # Insert text in a string or a file before the last occurence of a string.
73
+ # original: the original string or filename
74
+ # tag: occurence of string to find
75
+ # text: string to insert
76
+ # is_file: say if original is a file (default: true) or a string
77
+ def self.insert_before_last(original: nil, tag: nil, text: nil, is_file: true)
78
+ # The new text will be consolidated in content
79
+ content = ""
80
+
81
+ # If coming from a file, read original into content
82
+ if is_file
83
+ content = PadUtils.get_file_content(original)
84
+ else
85
+ content = original
86
+ end
87
+
88
+ # Find the position of tag in the string array and insert the text
89
+ positions = content.enum_for(:scan, /#{tag}/).map { Regexp.last_match.begin(0) }
90
+ content[positions.last - 1] = "#{text}"
91
+
92
+ # If coming from a file, write result in same file. If not,
93
+ # simply return content
94
+ if is_file
95
+ PadUtils.write_to_file(original, content)
96
+ return content
97
+ else
98
+ return content
99
+ end
100
+
101
+ rescue Exception => e
102
+ PadUtils.log("Error in insert_before_last", e)
103
+ end
104
+
105
+ # Insert text in a string or a file after the first occurence of a string.
106
+ # original: the original string or filename
107
+ # tag: occurence of string to find
108
+ # text: string to insert
109
+ # is_file: say if original is a file (default: true) or a string
110
+ def self.insert_after_first(original: nil, tag: nil, text: nil, is_file: true)
111
+ # The new text will be consolidated in content
112
+ content = ""
113
+
114
+ # If coming from a file, read original into content
115
+ if is_file
116
+ content = PadUtils.get_file_content(original)
117
+ else
118
+ content = original
119
+ end
120
+
121
+ # Iterate line by line. If a position is found, insert the text
122
+ # and set found to true to prevent further insertions
123
+ found = false
124
+ new_content = ""
125
+ content.each_line do |line|
126
+ position = line.index(/#{tag}/)
127
+ if position && !found
128
+ new_content += "#{line}#{text}"
129
+ found = true
130
+ else
131
+ new_content += line
132
+ end
133
+ end
134
+
135
+ # If coming from a file, write result in same file. If not,
136
+ # simply return content
137
+ if is_file
138
+ PadUtils.write_to_file(original, new_content)
139
+ return new_content
140
+ else
141
+ return new_content
142
+ end
143
+
144
+ rescue Exception => e
145
+ PadUtils.log("Error in insert_after_first", e)
146
+ end
147
+
148
+ # Insert text in a string or a file after the last occurence of a string.
149
+ # original: the original string or filename
150
+ # tag: occurence of string to find
151
+ # text: string to insert
152
+ # is_file: say if original is a file (default: true) or a string
153
+ def self.insert_after_last(original: nil, tag: nil, text: nil, is_file: true)
154
+ # The new text will be consolidated in content
155
+ content = ""
156
+
157
+ # If coming from a file, read original into content
158
+ if is_file
159
+ content = PadUtils.get_file_content(original)
160
+ else
161
+ content = original
162
+ end
163
+
164
+ # Find the position of tag in the string array and insert the text
165
+ positions = content.enum_for(:scan, /#{tag}/).map { Regexp.last_match.begin(0) }
166
+ content[positions.last + tag.length] = "#{text}"
167
+
168
+ # If coming from a file, write result in same file. If not,
169
+ # simply return content
170
+ if is_file
171
+ PadUtils.write_to_file(original, content)
172
+ return content
173
+ else
174
+ return content
175
+ end
176
+
177
+ rescue Exception => e
178
+ PadUtils.log("Error in insert_after_last", e)
179
+ end
180
+
181
+ end
@@ -0,0 +1,30 @@
1
+ require "time"
2
+
3
+ module PadUtils
4
+
5
+ # Return a string timestamp with the format: YYYYMMDDHHmmss
6
+ def self.time_to_stamp(val)
7
+ val.strftime("%Y%m%d%H%M%S")
8
+ end
9
+
10
+ # Return a Time object from a timestamp with the format: YYYYMMDDHHmmss
11
+ def self.stamp_to_time(val)
12
+ Time.parse "#{val[0..3]}-#{val[4..5]}-#{val[6..7]} #{val[8..9]}:#{val[10..11]}:#{val[12..13]}"
13
+ rescue Exception => e
14
+ PadUtils.log("Error in stamp_to_time", e)
15
+ end
16
+
17
+ # Return a string readable timestamp with format: YYYY-MM-DD HH:mm:ss
18
+ def self.time_to_readable_stamp(val)
19
+ val.strftime("%Y-%m-%d %H:%M:%S")
20
+ end
21
+
22
+ # Return a Time object from a PadUtils readable timestamp
23
+ # with format: YYYY-MM-DD HH:mm:ss
24
+ def self.readable_stamp_to_time(val)
25
+ Time.parse val
26
+ rescue Exception => e
27
+ PadUtils.log("Error in readable_stamp_to_time", e)
28
+ end
29
+
30
+ end
@@ -0,0 +1,3 @@
1
+ module PadUtils
2
+ VERSION = "1.1.1"
3
+ end
data/lib/pad_utils.rb ADDED
@@ -0,0 +1,22 @@
1
+ require_relative "pad_utils/version"
2
+ require_relative "pad_utils/pad_files"
3
+ require_relative "pad_utils/pad_text"
4
+ require_relative "pad_utils/pad_time"
5
+ require_relative "pad_utils/pad_logger"
6
+ require_relative "pad_utils/pad_menu"
7
+ require_relative "pad_utils/pad_json"
8
+
9
+ module PadUtils
10
+ # TODO: Add a cli coloring feature
11
+
12
+ def self.main(arg)
13
+ puts
14
+ puts "PadUtils v.#{PadUtils::VERSION}"
15
+ puts
16
+ puts "Part of the Padstone app builder (http://padstone.io)"
17
+ puts
18
+ puts "Copyright 2016 - Nico Schuele"
19
+ puts "Licensed under the Apache License, Version 2.0"
20
+ puts
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pad_utils
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Nico Schuele
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-02-21 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: PadUtils is a simple gem containing common utilities and shortcuts. It
14
+ is used in the [Padstone](http://padstone.io) app builder but can be embedded in
15
+ any other Ruby project.
16
+ email:
17
+ - help@padstone.io
18
+ executables:
19
+ - padutils
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - bin/padutils
27
+ - lib/pad_utils.rb
28
+ - lib/pad_utils/pad_files.rb
29
+ - lib/pad_utils/pad_json.rb
30
+ - lib/pad_utils/pad_logger.rb
31
+ - lib/pad_utils/pad_menu.rb
32
+ - lib/pad_utils/pad_text.rb
33
+ - lib/pad_utils/pad_time.rb
34
+ - lib/pad_utils/version.rb
35
+ homepage: http://padstone.io
36
+ licenses:
37
+ - Apache-2.0
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '2.2'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project:
55
+ rubygems_version: 2.5.1
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: PadUtils is a simple gem containing common utilities and shortcuts
59
+ test_files: []