cli_application 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +480 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/cli_application/app.rb +267 -0
- data/lib/cli_application/argv.rb +152 -0
- data/lib/cli_application/config.rb +82 -0
- data/lib/cli_application/databases.rb +39 -0
- data/lib/cli_application/includes.rb +21 -0
- data/lib/cli_application/json_struct.rb +48 -0
- data/lib/cli_application/stat.rb +170 -0
- data/lib/cli_application/version.rb +3 -0
- data/lib/cli_application.rb +21 -0
- data/test/cli_example.rb +25 -0
- data/test/examples/1/app.rb +26 -0
- data/test/examples/1/cli_example.rb +14 -0
- data/test/examples/1/stat/app.yml +33 -0
- data/test/examples/2/app.rb +28 -0
- data/test/examples/3/app.rb +25 -0
- data/test/examples/4/app.rb +49 -0
- data/test/examples/5/app.rb +33 -0
- data/test/examples/6/app.rb +31 -0
- data/test/examples/6/offer.rb +5 -0
- data/test/stat/rdebug-ide +21 -0
- data/test/stat/test_app.yml +29 -0
- data/test/test_app.rb +60 -0
- data/test/tovar.rb +5 -0
- metadata +145 -0
@@ -0,0 +1,267 @@
|
|
1
|
+
# CliApplication::App - основной класс - каркас CLI-приложений. Класс обеспечивает контроль
|
2
|
+
# аргументов командной строки, управление конфигами и подключениями к базе данных.
|
3
|
+
|
4
|
+
module CliApplication
|
5
|
+
class App
|
6
|
+
# Ссылка на класс, который содержит аргменты командной строки или значения по умолчанию
|
7
|
+
attr_reader :argv
|
8
|
+
# Код завершения приложения. Может быть использован в Bash-скриптах
|
9
|
+
attr_reader :exitcode
|
10
|
+
# Ссылка на массив, содержащий список директорий в которых исполняется приложение.
|
11
|
+
# Основные: folders[:app] - папка из которой запущено приложение, folders[:class] - папка,
|
12
|
+
# в которой хранится базовый класс проекта.
|
13
|
+
attr_reader :folders
|
14
|
+
# Ссылка на класс конфигурации приложения
|
15
|
+
attr_reader :config
|
16
|
+
# Строка - версия приложения
|
17
|
+
attr_reader :version
|
18
|
+
# Строка - описание приложения
|
19
|
+
attr_reader :description
|
20
|
+
# Строка - краткое описание (назначение) приложения
|
21
|
+
attr_reader :shortdescription
|
22
|
+
# Строка - дата релиза ПО
|
23
|
+
attr_reader :releasedate
|
24
|
+
# Структура, содержащая конфигурации баз данных
|
25
|
+
attr_reader :databases
|
26
|
+
# Строка-шаблон, вывод которой происходит после завершения работы приложения
|
27
|
+
attr_accessor :footer
|
28
|
+
|
29
|
+
# Конструктор экземпляра приложения
|
30
|
+
#
|
31
|
+
# @param [Array] argv аргументы командной строки
|
32
|
+
# @param [String] appfolder директория, из которой запущено приложение
|
33
|
+
# @param [String] classfolder директория, в которой расположен базовый класс проекта
|
34
|
+
# @param [Sym] lang язык работы приложения (реализовано не полностью)
|
35
|
+
def initialize(argv, appfolder, classfolder, lang = :ru)
|
36
|
+
::StTools::Setup.setup(lang)
|
37
|
+
|
38
|
+
@folders = Hash.new
|
39
|
+
@folders[:app] = appfolder
|
40
|
+
@folders[:class] = classfolder
|
41
|
+
|
42
|
+
@argv = ::CliApplication::Argv.new(argv)
|
43
|
+
@stat = ::CliApplication::Stat.new(@folders)
|
44
|
+
@config = ::CliApplication::Config.new(@folders)
|
45
|
+
|
46
|
+
@databases = ::CliApplication::Databases.new(config.cli.databases)
|
47
|
+
|
48
|
+
@footer = nil
|
49
|
+
|
50
|
+
init_app
|
51
|
+
end
|
52
|
+
|
53
|
+
#-------------------------------------------------------------
|
54
|
+
#
|
55
|
+
# Функции для использования внутри функции main
|
56
|
+
#
|
57
|
+
#-------------------------------------------------------------
|
58
|
+
|
59
|
+
# Метод возвращает папку из которой запущено приложение или расположен базовый класс.
|
60
|
+
# Базовый класс обычно располагается в фиксированном месте, например, в папке cli корня проекта. Соответственно,
|
61
|
+
# если вызвать File.dirname(app.folder(:class)), то можно будет узнать корневую папку проекта
|
62
|
+
#
|
63
|
+
# @param [Sym] type тип возвращаемой папки
|
64
|
+
# @option type [Sym] :app папка, из которой запущено приложение (по умолчанию)
|
65
|
+
# @option type [Sym] :class папка, в которой хранится базовый класс
|
66
|
+
# @option type [Sym] :stat папка, в которой хранится статистика по приложению
|
67
|
+
# @return [String] папка, из которой запущено приложение или расположен базовый класс
|
68
|
+
def folder(type = :app)
|
69
|
+
warn "Предупреждение: тип папки '#{type.inspect}' неизвестен (допустимо #{@folders.keys.inspect})" unless @folders.keys.include?(type)
|
70
|
+
@folders[type]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Метод загружает конфиг и делает его доступным через единый интерфейс настроек конфигурации приложения (CliApplication::Config)
|
74
|
+
# При каждом вызове данного метода все конфиги перечитываются заново.
|
75
|
+
#
|
76
|
+
# @param [Sym] type параметр используется для указания местоположения конфига. Если указано :app или :class,
|
77
|
+
# то имя файла с конфигом будет дополнено папкой класса или приложения
|
78
|
+
# @option type [Sym] :app папка, из которой запущено приложение
|
79
|
+
# @option type [Sym] :class папка, в которой хранится базовый класс
|
80
|
+
# @option type [Sym] :absolute указывает на необходимость брать имя файла как задано разработчиком
|
81
|
+
# @return [Nil] нет
|
82
|
+
def add_config(filename, type)
|
83
|
+
@config.add(filename, type)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Метод возвращает имя приложения
|
87
|
+
#
|
88
|
+
# @return [String] имя приложения без параметров командной строки и пути
|
89
|
+
def exename
|
90
|
+
::StTools::System.exename
|
91
|
+
end
|
92
|
+
|
93
|
+
# Метод возвращает число секунд в формате Float с момента запуска приложения. В основном используется для показа
|
94
|
+
# времени выполнения приложения, но может быть вызван в любой момент из любого места приложения.
|
95
|
+
#
|
96
|
+
# @return [Float] число секунд с момента запуска приложения
|
97
|
+
# @example Примеры использования
|
98
|
+
# puts "С момента запуска прошло #{executed_at} сек." #=> "С момента запуска прошло 23.456435 сек."
|
99
|
+
def executed_at
|
100
|
+
@executed_at = (::Time.now - @started_at).to_f
|
101
|
+
end
|
102
|
+
|
103
|
+
# Метод устанавливает код, с которым будет завершена работа приложения.
|
104
|
+
#
|
105
|
+
# @param [Integer] code код завершения приложения, который будет передан в операционную систему (bash)
|
106
|
+
def exitcode=(code)
|
107
|
+
@exitcode = code
|
108
|
+
@stat.exitcode = code
|
109
|
+
end
|
110
|
+
|
111
|
+
# Метод устанавливает текущую версию приложения, которая потом отобразится в файле статистики
|
112
|
+
#
|
113
|
+
# @param [Integer] val строка с версией приложения
|
114
|
+
# @example Примеры использования
|
115
|
+
# app = CliApplication.new(ARGV, __dir__)
|
116
|
+
# app.version = '2.1'
|
117
|
+
def version=(val)
|
118
|
+
@version = val
|
119
|
+
@stat.version = val
|
120
|
+
end
|
121
|
+
|
122
|
+
# Метод устанавливает описание приложения, которое будет выведено при старте скрипта. Данный метод используется
|
123
|
+
# для формирования подсказок пользователю.
|
124
|
+
#
|
125
|
+
# @param [String] val строка с описанием приложения
|
126
|
+
# @example Примеры использования
|
127
|
+
# app = CliApplication.new(ARGV, __dir__)
|
128
|
+
# app.description = 'Данное приложение обеспечивает.... (c) .... и т.д.'
|
129
|
+
def description=(val)
|
130
|
+
@description = val
|
131
|
+
@stat.description = val
|
132
|
+
end
|
133
|
+
|
134
|
+
# Метод устанавливает краткое описание приложения, которое будет выведено при старте скрипта, а также
|
135
|
+
# отображено в файле статистики.
|
136
|
+
#
|
137
|
+
# @param [String] val строка с кратким описанием приложения
|
138
|
+
# @example Примеры использования
|
139
|
+
# app = CliApplication.new(ARGV, __dir__)
|
140
|
+
# app.shortdescription = 'Утилита форматирования диска'
|
141
|
+
def shortdescription=(val)
|
142
|
+
@shortdescription = val
|
143
|
+
@stat.shortdescription = val
|
144
|
+
end
|
145
|
+
|
146
|
+
# Метод устанавливает дату последнего изменения (выпуска) приложения. Используется в справочных целях
|
147
|
+
#
|
148
|
+
# @param [String] val строка датой релиза (выпуска) приложения
|
149
|
+
# @example Примеры использования
|
150
|
+
# app = CliApplication.new(ARGV, __dir__)
|
151
|
+
# app.releasedate = '2015-05-11'
|
152
|
+
def releasedate=(val)
|
153
|
+
@releasedate = val
|
154
|
+
@stat.releasedate = val
|
155
|
+
end
|
156
|
+
|
157
|
+
# Метод предназначен для подключения файлов-моделей ActiveRecords. Архитектура CLI-приложения, учитывающая
|
158
|
+
# совместимость с Rails-проектами, требует загрузки моделей после чтения файлов конфигурации и, соответственно,
|
159
|
+
# иницииации класса приложения. Поэтому объявить require файлов моделей в начале файла не получится, будут
|
160
|
+
# выводится ошибки инициализации базы данных.
|
161
|
+
#
|
162
|
+
# @example Примеры использования
|
163
|
+
# def init_active_records
|
164
|
+
# require 'offers.rb'
|
165
|
+
# require 'params.rb'
|
166
|
+
# require 'categories.rb'
|
167
|
+
# end
|
168
|
+
def init_active_records
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
# Метод инициализации приложения. Может быть переписан с обязательным вызовом функции super
|
173
|
+
#
|
174
|
+
# @example Примеры использования
|
175
|
+
# def init_app
|
176
|
+
# super
|
177
|
+
#
|
178
|
+
# # Код своего приложения
|
179
|
+
# end
|
180
|
+
def init_app
|
181
|
+
@stat.last_started_at = ::Time.zone.now
|
182
|
+
@started_at = ::Time.now
|
183
|
+
@exitcode = 0
|
184
|
+
|
185
|
+
init_active_records
|
186
|
+
end
|
187
|
+
|
188
|
+
# Метод добавления аргумента командной строки. Вызывается при инициализации приложения, служит для определения списка
|
189
|
+
# аргументов командной строки, формирвоания подсказок и установки значения по умолчанию. В классе принят не традиционный
|
190
|
+
# для Linux формат командной строки. Пример вызова: add_city.rb user_id=123 name=Максим city='Верхние Луки'.
|
191
|
+
#
|
192
|
+
# Параметры, добавленные данным методом доступны через переменную argv (см. примеры)
|
193
|
+
#
|
194
|
+
# @param [Sym] action параметр определяет действие, которое надо произвести над параметром командной строки.
|
195
|
+
# @param [String] key название ключа, напрмиер 'user_id', 'name', 'city'.
|
196
|
+
# @param [Object] default значение по умочланию, "подставляемое" при отсутствии заданного пользователем параметра
|
197
|
+
# @param [String] description описание параметра (подсказка)
|
198
|
+
#
|
199
|
+
# @example Примеры использования
|
200
|
+
# app = CliApplication.new(ARGV, __dir__)
|
201
|
+
# app.set_argv(:integer, 'user_id', 0, 'Идентификатор пользователя')
|
202
|
+
# app.set_argv(:string, 'name', 'Без имени', 'Имя пользователя')
|
203
|
+
# app.set_argv(:caps, 'city', 'москВА', 'Город проживания пользователя')
|
204
|
+
#
|
205
|
+
# def main
|
206
|
+
# puts argv.user_id #=> 0
|
207
|
+
# puts argv.name #=> 'Без имени'
|
208
|
+
# puts argv.city #=> 'Москва'
|
209
|
+
# end
|
210
|
+
def set_argv(action, key, default, description)
|
211
|
+
@argv.set_argv(action, key, default, description)
|
212
|
+
end
|
213
|
+
|
214
|
+
# Основной метод, в котором должен быть размещен код приложения
|
215
|
+
# @return [Integer] метод должен возвращать код, который будет транслирован в параметр exitcode
|
216
|
+
def main
|
217
|
+
warn "ПРЕДУПРЕЖДЕНИЕ: необходимо переопределить функцию 'main' в вашем коде"
|
218
|
+
255
|
219
|
+
end
|
220
|
+
|
221
|
+
# При вызове данного метода начнется выполнение кода приложения (будет осуществен вызов функции main)
|
222
|
+
def run
|
223
|
+
self.exitcode = main || 255
|
224
|
+
self.executed_at = (::Time.now - @started_at).to_f
|
225
|
+
puts_footer
|
226
|
+
@stat.save
|
227
|
+
end
|
228
|
+
|
229
|
+
# Метод отображает на экране информацию о приложении (версия, дата последнего запуска, дата релиза, и пр.)
|
230
|
+
# @param [Syn] type при указании :full выводится полное описание, при других значениях не выводится
|
231
|
+
# подсказка по аргументам командной строки
|
232
|
+
def help(type = :full)
|
233
|
+
last_started_at_human = @stat.last_started_at_human
|
234
|
+
|
235
|
+
puts ::StTools::System.exename + ' - ' + @shortdescription
|
236
|
+
puts "Версия #{@version} (#{@releasedate})"
|
237
|
+
puts last_started_at_human
|
238
|
+
puts @stat.startes_human
|
239
|
+
puts
|
240
|
+
puts @description
|
241
|
+
|
242
|
+
if type == :full
|
243
|
+
@argv.help
|
244
|
+
puts
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
|
249
|
+
private
|
250
|
+
|
251
|
+
|
252
|
+
def puts_footer
|
253
|
+
return if @footer.nil?
|
254
|
+
line = footer.gsub('{executed_at}', executed_at.to_s)
|
255
|
+
line.gsub!('{memory}', StTools::Human.memory)
|
256
|
+
line.gsub!('{exitcode}', @exitcode.to_s)
|
257
|
+
line.gsub!('{status}', (@exitcode == 0 ? 'SUCCESS' : 'FAIL'))
|
258
|
+
puts line
|
259
|
+
end
|
260
|
+
|
261
|
+
def executed_at=(at)
|
262
|
+
@executed_at = at
|
263
|
+
@stat.executed_at = at
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# Данный класс обеспечивает управление аргументами командной строки
|
2
|
+
|
3
|
+
module CliApplication
|
4
|
+
class Argv < OpenStruct
|
5
|
+
|
6
|
+
# Конструктор. Вызывается при создании класса приложения. Данный класс доступен
|
7
|
+
# в главной функции приложения (main) через переменную argv
|
8
|
+
#
|
9
|
+
# @param [Array] argv аргументы командной строки, введенные пользователем
|
10
|
+
# @example Примеры использования
|
11
|
+
# puts argv.city #=> 'Москва'
|
12
|
+
def initialize(argv)
|
13
|
+
@params = Hash.new
|
14
|
+
@full = Hash.new
|
15
|
+
|
16
|
+
argv.each do |one|
|
17
|
+
if one.match(/[a-z\_0-9]\=/i)
|
18
|
+
pair = one.split('=')
|
19
|
+
@params[pair.first.to_s.strip.downcase.to_sym] = pair.last
|
20
|
+
else
|
21
|
+
warn "WARNING: некорректный ключ параметра командной строки: #{one.inspect} (#{File.basename(__FILE__)} at #{__LINE__})"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
super(@params)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Метод добавления аргумента командной строки. Вызывается при инициализации приложения, служит для определения списка
|
28
|
+
# аргументов командной строки, формирвоания подсказок и установки значения по умолчанию. В классе принят не традиционный
|
29
|
+
# для Linux формат командной строки. Пример вызова: add_city.rb user_id=123 name=Максим city='Верхние Луки'.
|
30
|
+
#
|
31
|
+
# Параметры, добавленные данным методом доступны через переменную argv (см. примеры)
|
32
|
+
#
|
33
|
+
# @param [Sym] action параметр определяет действие, которое надо произвести над параметром командной строки.
|
34
|
+
# @param [String] key название ключа, напрмиер 'user_id', 'name', 'city'.
|
35
|
+
# @param [Object] default значение по умочланию, "подставляемое" при отсутствии заданного пользователем параметра
|
36
|
+
# @param [String] description описание параметра (подсказка)
|
37
|
+
#
|
38
|
+
# @example Примеры использования
|
39
|
+
# app = CliApplication.new(ARGV, __dir__)
|
40
|
+
# app.set_argv(:integer, 'user_id', 0, 'Идентификатор пользователя')
|
41
|
+
# app.set_argv(:string, 'name', 'Без имени', 'Имя пользователя')
|
42
|
+
# app.set_argv(:caps, 'city', 'москВА', 'Город проживания пользователя')
|
43
|
+
#
|
44
|
+
# def main
|
45
|
+
# puts argv.user_id #=> 0
|
46
|
+
# puts argv.name #=> 'Без имени'
|
47
|
+
# puts argv.city #=> 'Москва'
|
48
|
+
# end
|
49
|
+
def set_argv(action, key, default, description)
|
50
|
+
key = key.downcase.strip.to_sym
|
51
|
+
unless @params.keys.include?(key)
|
52
|
+
@params[key] = default
|
53
|
+
end
|
54
|
+
|
55
|
+
case action
|
56
|
+
when :bool, :boolean
|
57
|
+
@params[key] = @params[key].to_s.to_bool
|
58
|
+
when :split
|
59
|
+
@params[key] = ::StTools::String.split(@params[key].to_s, ',', sort: true)
|
60
|
+
when :range
|
61
|
+
@params[key] = @params[key].to_s.to_range(sort: true, uniq: true)
|
62
|
+
when :range_no_uniq
|
63
|
+
@params[key] = @params[key].to_s.to_range(sort: true)
|
64
|
+
when :float
|
65
|
+
@params[key] = @params[key].to_s.strip.to_f
|
66
|
+
when :integer
|
67
|
+
@params[key] = @params[key].to_s.strip.to_i
|
68
|
+
when :downcase
|
69
|
+
@params[key] = @params[key].to_s.downcase
|
70
|
+
when :upcase
|
71
|
+
@params[key] = @params[key].to_s.upcase
|
72
|
+
when :normalize
|
73
|
+
@params[key] = @params[key].to_s.normalize
|
74
|
+
when :caps
|
75
|
+
@params[key] = @params[key].to_s.caps
|
76
|
+
when :string
|
77
|
+
@params[key] = @params[key].to_s
|
78
|
+
else
|
79
|
+
end
|
80
|
+
|
81
|
+
convert_from_hash
|
82
|
+
set_full(action, key, default, @params[key], description)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Метод выводит подсказку по аргументам командной строки
|
86
|
+
def help
|
87
|
+
puts
|
88
|
+
puts "Параметры приложения:"
|
89
|
+
|
90
|
+
screenwidth = ::StTools::System.screen(:width)
|
91
|
+
keylen = self.keylen
|
92
|
+
|
93
|
+
@full.each do |key, data|
|
94
|
+
line = get_helpline(key, data[:description], keylen, screenwidth)
|
95
|
+
line.each { |x| puts x }
|
96
|
+
end
|
97
|
+
puts
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def set_full(action, key, default, value, description)
|
103
|
+
@full[key] = Hash.new
|
104
|
+
@full[key][:action] = action
|
105
|
+
@full[key][:default] = default
|
106
|
+
@full[key][:value] = value
|
107
|
+
@full[key][:description] = description + ' ' + human_default(action, value, default)
|
108
|
+
end
|
109
|
+
|
110
|
+
def human_default(action, value, default)
|
111
|
+
type = value.class.to_s
|
112
|
+
defval = default.inspect
|
113
|
+
"(по умолчанию #{defval}:#{type})"
|
114
|
+
end
|
115
|
+
|
116
|
+
def keylen
|
117
|
+
keylen = 0
|
118
|
+
@full.each do |key, data|
|
119
|
+
keylen = key.to_s.length if key.to_s.length > keylen
|
120
|
+
end
|
121
|
+
keylen
|
122
|
+
end
|
123
|
+
|
124
|
+
def get_helpline(key, line, keylen, screenwidth)
|
125
|
+
out = Array.new
|
126
|
+
width = screenwidth - 2 - keylen - 3
|
127
|
+
chunks = line.chars.each_slice(width).map(&:join)
|
128
|
+
|
129
|
+
chunks.each do |one|
|
130
|
+
if out.count == 0
|
131
|
+
tmp = key.to_s.ljust(keylen, ' ') + ' - '
|
132
|
+
else
|
133
|
+
tmp = ' '.ljust(keylen, ' ') + ' '
|
134
|
+
end
|
135
|
+
out << " #{tmp}#{one.strip}"
|
136
|
+
out
|
137
|
+
end
|
138
|
+
|
139
|
+
out
|
140
|
+
end
|
141
|
+
|
142
|
+
def convert_from_hash
|
143
|
+
@params.each do |key, value|
|
144
|
+
name = new_ostruct_member(key)
|
145
|
+
self[name] = value
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# Класс обеспечивает чтение различных конфиг-файлов и их объединение в единый интерфейс.
|
2
|
+
# Например, при задании конфига вида
|
3
|
+
#
|
4
|
+
# cli:
|
5
|
+
# timezone: 3
|
6
|
+
#
|
7
|
+
# к указанным переменным можно получить доступ через вызов puts config.cli.timezone #=> 3
|
8
|
+
#
|
9
|
+
|
10
|
+
module CliApplication
|
11
|
+
class Config < OpenStruct
|
12
|
+
attr_reader :config
|
13
|
+
|
14
|
+
# Конструктор. Вызывается при создании класса приложения. Данный класс доступен
|
15
|
+
# в главной функции приложения (main) через переменную config
|
16
|
+
#
|
17
|
+
# @param [Array] folders директории, в которых расположены базовый класс проекта и класс приложения
|
18
|
+
def initialize(folders)
|
19
|
+
super(nil)
|
20
|
+
return if folders.nil?
|
21
|
+
@folders = folders
|
22
|
+
@filenames = Array.new
|
23
|
+
@config_filename = File.join([folders[:class], 'config.yml'])
|
24
|
+
load_config(@config_filename)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Метод загружает конфиг и делает его доступным через единый интерфейс настроек конфигурации приложения (CliApplication::Config)
|
28
|
+
# При каждом вызове данного метода все конфиги перечитываются заново.
|
29
|
+
#
|
30
|
+
# @param [Sym] type параметр используется для указания местоположения конфига. Если указано :app или :class,
|
31
|
+
# то имя файла с конфигом будет дополнено папкой класса или приложения
|
32
|
+
# @option type [Sym] :app папка, из которой запущено приложение
|
33
|
+
# @option type [Sym] :class папка, в которой хранится базовый класс
|
34
|
+
# @option type [Sym] :absolute указывает на необходимость брать имя файла как задано разработчиком
|
35
|
+
# @return [Nil] нет
|
36
|
+
def add(filename, type)
|
37
|
+
if @folders.keys.include?(type)
|
38
|
+
load_config(File.join(@folders[type], filename))
|
39
|
+
elsif type == :absolute
|
40
|
+
load_config(filename)
|
41
|
+
else
|
42
|
+
warn "Предупреждение: попытка загрузить конфиг неизвестного типа (#{type.inspect}). Допустимы #{@folders.keys.inspect}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
|
50
|
+
def load_config(filename) # :nodoc:
|
51
|
+
raise "Внимание!!! Не найден файл конфигурации '#{filename}'" unless File.exist?(filename)
|
52
|
+
@filenames << filename
|
53
|
+
@filenames.uniq!
|
54
|
+
@config = Hash.new
|
55
|
+
|
56
|
+
@filenames.each do |one|
|
57
|
+
tmp = YAML.load_file(one).deep_symbolize_keys rescue Hash.new
|
58
|
+
@config.merge!(tmp)
|
59
|
+
end
|
60
|
+
|
61
|
+
tmp = JsonStruct.new(@config)
|
62
|
+
tmp.each_pair { |key, value| set_pair(key, value) }
|
63
|
+
valid?
|
64
|
+
|
65
|
+
::Time.zone = self.cli.timezone
|
66
|
+
# todo: добавить установки времени для записей ActiveRecord
|
67
|
+
end
|
68
|
+
|
69
|
+
def set_pair(key, value) # :nodoc:
|
70
|
+
name = new_ostruct_member(key)
|
71
|
+
self[name] = value
|
72
|
+
end
|
73
|
+
|
74
|
+
def valid? # :nodoc:
|
75
|
+
raise "ОШИБКА: не найдена секция 'cli'" if self.cli.nil?
|
76
|
+
raise "ОШИБКА: не найдена секция 'cli.tz'" if self.cli.timezone.nil?
|
77
|
+
raise "ОШИБКА: не найдена секция 'cli.active_record_tz'" if self.cli.ar_timezone.nil?
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Класс обесечивает формирвоание конфигураций баз данных в совместимом с Rails формате
|
2
|
+
|
3
|
+
module CliApplication
|
4
|
+
class Databases
|
5
|
+
|
6
|
+
# Конструктор, который обеспечивает конфигурацию базового класса ActiveRecords::Base,
|
7
|
+
# а именно загружает в класс все конфигурации, с которыми должно работать приложение.
|
8
|
+
def initialize(config)
|
9
|
+
@config = config.to_h || Hash.new
|
10
|
+
ar_configuration
|
11
|
+
end
|
12
|
+
|
13
|
+
# Метод возвращает список конфигураций баз данных
|
14
|
+
#
|
15
|
+
# @return [Array] массив названий конфигураций
|
16
|
+
# @example Примеры использования
|
17
|
+
# puts databases.list #=> [:default, :stat, :work_instance]
|
18
|
+
def list
|
19
|
+
@config.keys
|
20
|
+
end
|
21
|
+
|
22
|
+
# Метод возвращает конфигурацию базы данных
|
23
|
+
#
|
24
|
+
# @param [Sym] ind идентификатор (наименование) конфигурации базы данных
|
25
|
+
# @return [Hash] конфигурация базы данных
|
26
|
+
def [](ind)
|
27
|
+
@config[ind]
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def ar_configuration # :nodoc:
|
33
|
+
list.each do |cfg_name|
|
34
|
+
ActiveRecord::Base.configurations[cfg_name] = @config[cfg_name].symbolize_keys
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Расширяем стандартные классы, подмешивая туда функционал StTools
|
2
|
+
|
3
|
+
class String # :nodoc:
|
4
|
+
include ::StTools::Module::String
|
5
|
+
end
|
6
|
+
|
7
|
+
class Integer # :nodoc:
|
8
|
+
include ::StTools::Module::Integer
|
9
|
+
end
|
10
|
+
|
11
|
+
class Time # :nodoc:
|
12
|
+
include ::StTools::Module::Time
|
13
|
+
end
|
14
|
+
|
15
|
+
class Date # :nodoc:
|
16
|
+
include ::StTools::Module::Time
|
17
|
+
end
|
18
|
+
|
19
|
+
# class DateTime
|
20
|
+
# include ::StTools::Module::Time
|
21
|
+
# end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# https://gist.github.com/anonymous/0ea3a14166d24f750bd9
|
2
|
+
|
3
|
+
class JsonStruct < OpenStruct # :nodoc:
|
4
|
+
def initialize(hash=nil)
|
5
|
+
|
6
|
+
@table = {}
|
7
|
+
@hash_table = {}
|
8
|
+
|
9
|
+
if hash
|
10
|
+
recurse = Proc.new do |item|
|
11
|
+
values = []
|
12
|
+
|
13
|
+
item.each do |val|
|
14
|
+
if val.is_a?(Hash)
|
15
|
+
values.push(self.class.new(val))
|
16
|
+
elsif val.is_a?(Array)
|
17
|
+
values.push(recurse.call(val))
|
18
|
+
else
|
19
|
+
values.push(val)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
item.clear
|
24
|
+
item.push(*values)
|
25
|
+
|
26
|
+
item
|
27
|
+
end
|
28
|
+
|
29
|
+
hash.each do |k, v|
|
30
|
+
|
31
|
+
if v.is_a?(Array)
|
32
|
+
recurse.call(v)
|
33
|
+
end
|
34
|
+
|
35
|
+
@table[k.to_sym] = (v.is_a?(Hash) ? self.class.new(v) : v)
|
36
|
+
@hash_table[k.to_sym] = v
|
37
|
+
new_ostruct_member(k)
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_h
|
44
|
+
@hash_table
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|