mech 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +20 -0
- data/README.md +119 -0
- data/README.rdoc +19 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/conf.rb +8 -0
- data/lib/mech.rb +69 -0
- data/lib/mech/compiler.rb +7 -0
- data/lib/mech/compiler/format.rb +27 -0
- data/lib/mech/compiler/format/action_script.rb +2 -0
- data/lib/mech/compiler/format/cl.rb +2 -0
- data/lib/mech/compiler/format/java_script.rb +15 -0
- data/lib/mech/compiler/format/ruby.rb +2 -0
- data/lib/mech/compiler/format/scala.rb +2 -0
- data/lib/mech/compiler/format/yaml.rb +15 -0
- data/lib/mech/compiler/tmp/action_script.erb +1 -0
- data/lib/mech/compiler/tmp/cl.erb.erb +1 -0
- data/lib/mech/compiler/tmp/java_script.erb +1 -0
- data/lib/mech/compiler/tmp/ruby.erb.erb +1 -0
- data/lib/mech/compiler/tmp/scala.erb +1 -0
- data/lib/mech/compiler/tmp/yaml.erb +2 -0
- data/lib/mech/config.rb +29 -0
- data/lib/mech/configurator.rb +21 -0
- data/lib/mech/path_loader.rb +26 -0
- data/lib/mech/producer.rb +9 -0
- data/lib/mech/producer/common.rb +83 -0
- data/lib/mech/producer/default.rb +90 -0
- data/lib/src/common.yml +1 -0
- data/lib/src/env/item.yml +1 -0
- data/lib/src/env/item/items.yml +1 -0
- data/lib/src/item.yml +1 -0
- data/mech.gemspec +86 -0
- data/test/helper.rb +18 -0
- data/test/test_mech.rb +7 -0
- metadata +132 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "shoulda", ">= 0"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "jeweler", "~> 1.6.4"
|
12
|
+
gem "rcov", ">= 0"
|
13
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.6.4)
|
6
|
+
bundler (~> 1.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
rake (0.9.2.2)
|
10
|
+
rcov (0.9.11)
|
11
|
+
shoulda (2.11.3)
|
12
|
+
|
13
|
+
PLATFORMS
|
14
|
+
ruby
|
15
|
+
|
16
|
+
DEPENDENCIES
|
17
|
+
bundler (~> 1.0.0)
|
18
|
+
jeweler (~> 1.6.4)
|
19
|
+
rcov
|
20
|
+
shoulda
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Kazantsev Nickolay
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
Концепция структуры конфигурационных файлов
|
2
|
+
====
|
3
|
+
|
4
|
+
Есть 2 папки - SRC и BIN. В SRC находятся YAML-файлы конфигурации в структуре вложенных папок отражающей наследование. В BIN помещаются сгруппированные файлы конфигурации в заданном формате (после компиляции).
|
5
|
+
|
6
|
+
Прототип - объект конфигурации (список ключ-значение и имя)
|
7
|
+
|
8
|
+
Пример:
|
9
|
+
|
10
|
+
```yaml
|
11
|
+
item_name_123:
|
12
|
+
id: 100500
|
13
|
+
name: Item Name
|
14
|
+
field: "Field value"
|
15
|
+
```
|
16
|
+
|
17
|
+
Метапрототип - объект на который накладываются данные из прототипа, с целью получения результирующего прототипа.
|
18
|
+
|
19
|
+
Пример:
|
20
|
+
|
21
|
+
```yaml
|
22
|
+
bot: true
|
23
|
+
shopable: true
|
24
|
+
states:
|
25
|
+
- { name: "State 1", period: 1s }
|
26
|
+
- { name: "State 2", period: 1s }
|
27
|
+
```
|
28
|
+
|
29
|
+
Результирующий прототип - прототип получающийся в результате объединения нескольких метапрототипов (по иерархии) и исходного прототипа.
|
30
|
+
|
31
|
+
Пример
|
32
|
+
|
33
|
+
```yaml
|
34
|
+
item_name_123:
|
35
|
+
id: 100500
|
36
|
+
name: Item Name
|
37
|
+
field: "Field value"
|
38
|
+
bot: true
|
39
|
+
shopable: true
|
40
|
+
states:
|
41
|
+
- name: "State 1"
|
42
|
+
period: 1s
|
43
|
+
- name: "State 2"
|
44
|
+
period: 1s
|
45
|
+
```
|
46
|
+
|
47
|
+
SRC представляет собой следующую структуру
|
48
|
+
|
49
|
+
```
|
50
|
+
src_path/common.yml - базовая конфигурация
|
51
|
+
src_path/item.yml - конфигурация для базового метапрототипа Item
|
52
|
+
src_path/quest.yml - для Quest
|
53
|
+
src_path/env1/ - Конфигурация для окружения env1
|
54
|
+
src_path/env1/item.yml - Базовая конфигурация метапрототипа Item в окружении env1
|
55
|
+
src_path/env1/quest.yml - Quest в env2
|
56
|
+
src_path/env1/item/items.yml - Конфигурация прототипов Item
|
57
|
+
src_path/env1/item/quest_items.yml - прототипы Quest
|
58
|
+
src_path/env2/ - Конфигурация для окружения env2
|
59
|
+
src_path/env2/...
|
60
|
+
```
|
61
|
+
|
62
|
+
Каждый прототип из src_path/env1/item/items.yml или src_path/env1/item/quest_items.yml накладывается последовательно на своих родителей. То есть каждый прототип из src_path/env1/item/items.yml накладывается сначала на src_path/env1/item.yml, потом на src_path/item.yml и в конце на src_path/common.yml. Результирующий список прототипов (снимок) имеет те же имена объектов, что были перечислены первоначально в src_path/env1/item/items.yml.
|
63
|
+
|
64
|
+
Компиляция
|
65
|
+
-----
|
66
|
+
|
67
|
+
Получившийся снимок может быть скомпилирован и помещен в BIN в соответствии с именем своего базового метапрототипа. То есть для всех объектов из src_path/env1/item.yml с генерируется файл bin_src/env_1_item.<расширение формата> в соответствии с форматом компиляции.
|
68
|
+
|
69
|
+
Наследование метапрототипов
|
70
|
+
-----
|
71
|
+
|
72
|
+
Метапрототипы могут представлять иерархическую структуру наследования. Например в приведенном примере представлена двухуровневая структура наследования для базовых метапрототипов Item и Quest.
|
73
|
+
|
74
|
+
```
|
75
|
+
Item
|
76
|
+
|-----> Build
|
77
|
+
|-----> Unit
|
78
|
+
|
79
|
+
Quest
|
80
|
+
|-----> History (Story)
|
81
|
+
|-----> Battle
|
82
|
+
```
|
83
|
+
|
84
|
+
При этом предполагается, что на основе иерархии наследования можно вводить любое число метапототипов (увеличивая уровень наследования), получая необходимые сущности для приложения.
|
85
|
+
|
86
|
+
Данная структура исключает множественное наследование, в пользу простого наследования.
|
87
|
+
|
88
|
+
Фичарсы
|
89
|
+
-----
|
90
|
+
|
91
|
+
+ Возможность автоматической сборки прототипов на любом уровне иерархии (например YAML, Syck, Psych)
|
92
|
+
+ Возможность изменять объект любого уровня в иерархии метапрототипов готовыми библиотеками (например Psych, Syck, Psych) не опасаясь нарушить структуру данных (развернутый merge, битые alias)
|
93
|
+
+ Интуитивно понятное расположение файлов по аналогии с иерархией классов
|
94
|
+
+ Возможность распределение прав доступа на редактирование отдельных метапрототипов или переопределяемых полей в результирующем прототипе
|
95
|
+
+ Расширяемость. Возможность изменения механизма сбора данных (из SRC) и расширения форматов компиляции
|
96
|
+
|
97
|
+
Текущее состояние реализации
|
98
|
+
-----
|
99
|
+
|
100
|
+
* Имеется общий конфигурационный файл позволяющий задавать произвольные пути для BIN и SRC. Этот файл также может быть помещен в произвольные места текущего проекта.
|
101
|
+
* Поддержка сборки данных (создания снимка) в описанном формате
|
102
|
+
* Есть поддержка компиляции в формат JSON (JavaScript) и YAML
|
103
|
+
|
104
|
+
Запуск
|
105
|
+
-----
|
106
|
+
|
107
|
+
Для запуска нужно открыть irb в корне репозитория и выполнить
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
require './mech'
|
111
|
+
puts Mech.compile
|
112
|
+
```
|
113
|
+
|
114
|
+
TODO
|
115
|
+
-----
|
116
|
+
|
117
|
+
* Реализовать произвольную глубину вложенности для базовый метапрототипов. Сейчас структура у Quest должна быть равна по глубине структуре Item, в противном случае в общий снимок попадут данные только для самой глубокой иерархии метапрототипа.
|
118
|
+
* Написать тесты для различных вариантов конфигурации
|
119
|
+
* Сделать интерфейс для редактирования прототипов и метапрототипов
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= mech
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Contributing to mech
|
6
|
+
|
7
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
8
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
9
|
+
* Fork the project
|
10
|
+
* Start a feature/bugfix branch
|
11
|
+
* Commit and push until you are happy with your contribution
|
12
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2011 Kazantsev Nickolay. See LICENSE.txt for
|
18
|
+
further details.
|
19
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "mech"
|
18
|
+
gem.homepage = "http://github.com/realb0t/mech"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = "Build config formats from nested yaml"
|
21
|
+
gem.description = "Build config formats from nested yaml"
|
22
|
+
gem.email = "kazantsev.nickolay@gmail.com"
|
23
|
+
gem.authors = ["Kazantsev Nickolay"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/test_*.rb'
|
39
|
+
test.verbose = true
|
40
|
+
test.rcov_opts << '--exclude "gems/*"'
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "mech #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/conf.rb
ADDED
data/lib/mech.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'find'
|
2
|
+
require 'yaml'
|
3
|
+
require 'psych'
|
4
|
+
|
5
|
+
unless {}.respond_to?(:deep_merge)
|
6
|
+
class Hash
|
7
|
+
def deep_merge(*args)
|
8
|
+
merge(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def deep_merge!(*args)
|
12
|
+
merge!(*args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Mech
|
18
|
+
|
19
|
+
VERSION = [ 0, 0, 1 ]
|
20
|
+
|
21
|
+
def self.auto_path(path)
|
22
|
+
File.join(File.dirname(__FILE__), path)
|
23
|
+
end
|
24
|
+
|
25
|
+
autoload :Configurator, File.join(File.dirname(__FILE__), 'mech/configurator')
|
26
|
+
autoload :Config, File.join(File.dirname(__FILE__), 'mech/config')
|
27
|
+
autoload :Compiler, File.join(File.dirname(__FILE__), 'mech/compiler')
|
28
|
+
autoload :Producer, File.join(File.dirname(__FILE__), 'mech/producer')
|
29
|
+
autoload :PathLoader, File.join(File.dirname(__FILE__), 'mech/path_loader')
|
30
|
+
|
31
|
+
class Producer
|
32
|
+
autoload :Common , File.join(File.dirname(__FILE__), 'mech/producer/common')
|
33
|
+
autoload :Default, File.join(File.dirname(__FILE__), 'mech/producer/default')
|
34
|
+
end
|
35
|
+
|
36
|
+
class Compiler
|
37
|
+
autoload :Format, File.join(File.dirname(__FILE__), 'mech/compiler/format')
|
38
|
+
|
39
|
+
class Format
|
40
|
+
autoload :Yaml, File.join(File.dirname(__FILE__),
|
41
|
+
'mech/compiler/format/yaml')
|
42
|
+
|
43
|
+
autoload :JavaScript, File.join(File.dirname(__FILE__),
|
44
|
+
'mech/compiler/format/java_script')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class << self
|
49
|
+
|
50
|
+
include Mech::Configurator
|
51
|
+
|
52
|
+
def compile(params = {})
|
53
|
+
producer_name = params[:producer_name] || config.producer
|
54
|
+
compile_format = params[:compiler_format] || config.compiler
|
55
|
+
config_path = params[:config_path]
|
56
|
+
|
57
|
+
init(config_path) if config_path
|
58
|
+
|
59
|
+
loader = Mech::PathLoader.new(config)
|
60
|
+
producer = Mech::Producer.const_get(producer_name).new(loader.paths)
|
61
|
+
compiler = Mech::Compiler.build(compile_format)
|
62
|
+
|
63
|
+
data = producer.produce
|
64
|
+
|
65
|
+
compiler.compile(data)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
class Mech::Compiler::Format
|
4
|
+
|
5
|
+
include Mech::Configurator
|
6
|
+
|
7
|
+
def compile(data, params = {}, &block)
|
8
|
+
raise 'Compile method not exist'
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(*args)
|
12
|
+
@data = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def with_template
|
16
|
+
ERB.new(File.read(tmp_path)).result(binding)
|
17
|
+
end
|
18
|
+
|
19
|
+
def tmp_path
|
20
|
+
raise 'Not defined tmp path'
|
21
|
+
end
|
22
|
+
|
23
|
+
def output
|
24
|
+
@data
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class Mech::Compiler::Format::JavaScript < Mech::Compiler::Format
|
4
|
+
|
5
|
+
def tmp_path
|
6
|
+
@tmp_path ||= File.join(config.tmp_path, 'java_script.erb')
|
7
|
+
end
|
8
|
+
|
9
|
+
def compile(data, params = {})
|
10
|
+
@data = data
|
11
|
+
with_template
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= output %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= output %>
|
@@ -0,0 +1 @@
|
|
1
|
+
var Mech = { 'Config': <%= output.to_json %> };
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= output %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= output %>
|
data/lib/mech/config.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
class Mech::Config
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
def self.init(&block)
|
7
|
+
instance.init(&block)
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(variable, *args, &block)
|
11
|
+
if block_given?
|
12
|
+
args.unshift(self)
|
13
|
+
instance_variable_set("@#{variable}", lambda { block.call(*args) })
|
14
|
+
elsif args.size > 0
|
15
|
+
instance_variable_set("@#{variable}", args.shift)
|
16
|
+
else
|
17
|
+
value = instance_variable_get("@#{variable}")
|
18
|
+
value.respond_to?(:call) ? value.call : value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def env
|
23
|
+
enviropment || nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def init(&block)
|
27
|
+
instance_eval(&block)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Mech::Configurator
|
2
|
+
|
3
|
+
def init(path = nil)
|
4
|
+
require path || File.join(File.dirname(__FILE__), '..', 'conf')
|
5
|
+
@config ||= Mech::Config.instance
|
6
|
+
self
|
7
|
+
end
|
8
|
+
|
9
|
+
def config
|
10
|
+
unless @config
|
11
|
+
if init
|
12
|
+
@config ||= Mech::Config.instance
|
13
|
+
else
|
14
|
+
raise 'Not load config file'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
@config
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Mech::PathLoader
|
2
|
+
attr_accessor :paths
|
3
|
+
|
4
|
+
def initialize(config)
|
5
|
+
@paths = []
|
6
|
+
@config = config
|
7
|
+
find_paths
|
8
|
+
filter_paths_by_env
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def find_paths
|
14
|
+
Find.find(@config.src_path) { |f|
|
15
|
+
@paths.push(f) if f.match(/\.yml\Z/)
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def filter_paths_by_env
|
20
|
+
@paths.select! do |path|
|
21
|
+
path =~ Regexp.new(File.join(@config.src_path, @config.env))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
class Mech::Producer::Common < Mech::Producer
|
2
|
+
|
3
|
+
def produce
|
4
|
+
build_merge_graph
|
5
|
+
merge_recursive
|
6
|
+
end
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
def build_merge_graph
|
11
|
+
@paths_with_deep = @paths.map do |path|
|
12
|
+
path_deep = path.split('/').size
|
13
|
+
[path, path_deep]
|
14
|
+
end
|
15
|
+
@paths_with_deep.sort_by! { |p| p[1] }
|
16
|
+
@min_path_deep = @paths_with_deep.first[1]
|
17
|
+
@max_path_deep = @paths_with_deep.last[1]
|
18
|
+
end
|
19
|
+
|
20
|
+
def merge_recursive
|
21
|
+
@paths_with_deep.delete_if { |p| p[0] == '/common.yml' }
|
22
|
+
@common_obj = YAML.load(File.read(config.src_path + '/common.yml'))
|
23
|
+
|
24
|
+
@stored_paths = @paths_with_deep.select { |p, d|
|
25
|
+
d == @max_path_deep
|
26
|
+
}.map(&:first)
|
27
|
+
|
28
|
+
merged_items_by_path = @stored_paths.map do |stored_path|
|
29
|
+
extend_obj = build_extend_object(stored_path, {})
|
30
|
+
objs = Psych.load(File.read(stored_path))
|
31
|
+
|
32
|
+
objs.each do |name, obj|
|
33
|
+
objs[name] = @common_obj.deep_merge(extend_obj.deep_merge(obj))
|
34
|
+
end
|
35
|
+
|
36
|
+
env_path = File.join(config.src_path, config.env)
|
37
|
+
tail_path = stored_path.gsub(env_path, '')
|
38
|
+
meta_type = tail_path.split('/')[1]
|
39
|
+
|
40
|
+
[meta_type, objs]
|
41
|
+
end
|
42
|
+
|
43
|
+
items_by_meta_type = {}
|
44
|
+
merged_items_by_path.each do |meta, items|
|
45
|
+
items_by_meta_type[meta] ||= {}
|
46
|
+
items_by_meta_type[meta].deep_merge!(items)
|
47
|
+
end
|
48
|
+
|
49
|
+
merged_items_by_meta_type = {}
|
50
|
+
items_by_meta_type.each do |meta, items|
|
51
|
+
meta_data = get_meta_data(meta)
|
52
|
+
items.each do |name, item|
|
53
|
+
item = meta_data.deep_merge(item)
|
54
|
+
items_by_meta_type[meta][name] = item
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
items_by_meta_type
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_meta_data(meta_type)
|
62
|
+
path = File.join(config.src_path, "#{meta_type}.yml")
|
63
|
+
yaml = Psych.load(File.read(path))
|
64
|
+
end
|
65
|
+
|
66
|
+
def build_extend_object(path, pattern)
|
67
|
+
paths = path.split('/')
|
68
|
+
paths.pop
|
69
|
+
path = paths.join('/') + '.yml'
|
70
|
+
|
71
|
+
if File.exist?(path)
|
72
|
+
obj = Psych.load(File.read(path))
|
73
|
+
pattern = pattern.deep_merge(obj || {})
|
74
|
+
end
|
75
|
+
|
76
|
+
if path =~ Regexp.new(config.src_path)
|
77
|
+
pattern = build_extend_object(path, pattern)
|
78
|
+
end
|
79
|
+
|
80
|
+
pattern
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
class Mech::Producer::Default < Mech::Producer
|
2
|
+
|
3
|
+
def produce
|
4
|
+
@common_obj = Psych.load(File.read(config.src_path + '/common.yml'))
|
5
|
+
|
6
|
+
@meta_type_title = load_meta_type_titles - [ 'common' ]
|
7
|
+
@primary_meta_type_objs = load_meta_type_objs(config.src_path)
|
8
|
+
|
9
|
+
src_path = config.src_path
|
10
|
+
env = config.env
|
11
|
+
env_src_path = File.join(src_path, env)
|
12
|
+
|
13
|
+
@secodry_meta_type_objs = load_meta_type_objs(env_src_path)
|
14
|
+
|
15
|
+
contents = {}
|
16
|
+
@meta_type_title.each do |type|
|
17
|
+
contents[type] = load_dir_contents(File.join(env_src_path, type))
|
18
|
+
contents[type].each do |name, val|
|
19
|
+
meta_type_obj = @common_obj.deep_merge(@primary_meta_type_objs[type])
|
20
|
+
meta_type_obj = meta_type_obj.deep_merge(@secodry_meta_type_objs[type])
|
21
|
+
contents[type][name] = meta_type_obj.deep_merge(val)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
contents
|
26
|
+
end
|
27
|
+
|
28
|
+
def load_meta_type_titles
|
29
|
+
paths = Dir.new(config.src_path).find.to_a.select do |path|
|
30
|
+
path =~ /.*\.yml/
|
31
|
+
end
|
32
|
+
paths.map { |path| path.gsub(/\.yml/, '') }
|
33
|
+
end
|
34
|
+
|
35
|
+
def load_meta_type_objs(src_path)
|
36
|
+
paths = Dir.new(src_path).find.to_a.select do |path|
|
37
|
+
path =~ /.*\.yml/
|
38
|
+
end
|
39
|
+
|
40
|
+
keys = paths.map { |path| path.gsub(/\.yml/, '') }
|
41
|
+
|
42
|
+
values = paths.map do |path|
|
43
|
+
content = File.read(File.join(src_path, path))
|
44
|
+
Psych.load(content)
|
45
|
+
end
|
46
|
+
|
47
|
+
obj = {}
|
48
|
+
|
49
|
+
keys.each_with_index do |key, index|
|
50
|
+
obj[key] = values[index]
|
51
|
+
end
|
52
|
+
|
53
|
+
obj
|
54
|
+
end
|
55
|
+
|
56
|
+
def load_dir_contents(path)
|
57
|
+
dir = Dir.new(path)
|
58
|
+
|
59
|
+
dirs = dir.find.to_a.select { |name|
|
60
|
+
File.directory?(File.join(path, name)) && ! ['.', '..', '...'].include?(name)
|
61
|
+
}.map { |name| [name, File.join(path, name)] }
|
62
|
+
|
63
|
+
contents = dir.find.to_a.select { |name|
|
64
|
+
name =~ /\.yml/
|
65
|
+
}.map { |name|
|
66
|
+
[ name.gsub(/\.yml/, ''), Psych.load(File.read(File.join(path, name))) ]
|
67
|
+
}
|
68
|
+
contents = Hash[contents]
|
69
|
+
|
70
|
+
nested_contents = {}
|
71
|
+
dirs.each { |name, dir|
|
72
|
+
nested_contents[name] = load_dir_contents(dir)
|
73
|
+
}
|
74
|
+
|
75
|
+
if dirs.size.zero?
|
76
|
+
return contents.values.first
|
77
|
+
else
|
78
|
+
objs = {}
|
79
|
+
|
80
|
+
nested_contents.each do |type, scope|
|
81
|
+
scope.each do |name, v|
|
82
|
+
objs[name] = contents[type].deep_merge(v) if nested_contents[type][name]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
return objs
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
data/lib/src/common.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--- {}
|
@@ -0,0 +1 @@
|
|
1
|
+
--- {}
|
@@ -0,0 +1 @@
|
|
1
|
+
--- {}
|
data/lib/src/item.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--- {}
|
data/mech.gemspec
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{mech}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = [%q{Kazantsev Nickolay}]
|
12
|
+
s.date = %q{2011-11-23}
|
13
|
+
s.description = %q{Build config formats from nested yaml}
|
14
|
+
s.email = %q{kazantsev.nickolay@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.md",
|
18
|
+
"README.rdoc"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".document",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"LICENSE.txt",
|
25
|
+
"README.md",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"lib/conf.rb",
|
30
|
+
"lib/mech.rb",
|
31
|
+
"lib/mech/compiler.rb",
|
32
|
+
"lib/mech/compiler/format.rb",
|
33
|
+
"lib/mech/compiler/format/action_script.rb",
|
34
|
+
"lib/mech/compiler/format/cl.rb",
|
35
|
+
"lib/mech/compiler/format/java_script.rb",
|
36
|
+
"lib/mech/compiler/format/ruby.rb",
|
37
|
+
"lib/mech/compiler/format/scala.rb",
|
38
|
+
"lib/mech/compiler/format/yaml.rb",
|
39
|
+
"lib/mech/compiler/tmp/action_script.erb",
|
40
|
+
"lib/mech/compiler/tmp/cl.erb.erb",
|
41
|
+
"lib/mech/compiler/tmp/java_script.erb",
|
42
|
+
"lib/mech/compiler/tmp/ruby.erb.erb",
|
43
|
+
"lib/mech/compiler/tmp/scala.erb",
|
44
|
+
"lib/mech/compiler/tmp/yaml.erb",
|
45
|
+
"lib/mech/config.rb",
|
46
|
+
"lib/mech/configurator.rb",
|
47
|
+
"lib/mech/path_loader.rb",
|
48
|
+
"lib/mech/producer.rb",
|
49
|
+
"lib/mech/producer/common.rb",
|
50
|
+
"lib/mech/producer/default.rb",
|
51
|
+
"lib/src/common.yml",
|
52
|
+
"lib/src/env/item.yml",
|
53
|
+
"lib/src/env/item/items.yml",
|
54
|
+
"lib/src/item.yml",
|
55
|
+
"mech.gemspec",
|
56
|
+
"test/helper.rb",
|
57
|
+
"test/test_mech.rb"
|
58
|
+
]
|
59
|
+
s.homepage = %q{http://github.com/realb0t/mech}
|
60
|
+
s.licenses = [%q{MIT}]
|
61
|
+
s.require_paths = [%q{lib}]
|
62
|
+
s.rubygems_version = %q{1.8.6}
|
63
|
+
s.summary = %q{Build config formats from nested yaml}
|
64
|
+
|
65
|
+
if s.respond_to? :specification_version then
|
66
|
+
s.specification_version = 3
|
67
|
+
|
68
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
69
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
70
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
71
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
72
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
73
|
+
else
|
74
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
75
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
76
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
77
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
78
|
+
end
|
79
|
+
else
|
80
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
81
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
82
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
83
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'mech'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
data/test/test_mech.rb
ADDED
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mech
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Kazantsev Nickolay
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-23 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: shoulda
|
16
|
+
requirement: &84009020 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *84009020
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: bundler
|
27
|
+
requirement: &84008780 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.0.0
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *84008780
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: jeweler
|
38
|
+
requirement: &84008540 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.6.4
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *84008540
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rcov
|
49
|
+
requirement: &84008300 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *84008300
|
58
|
+
description: Build config formats from nested yaml
|
59
|
+
email: kazantsev.nickolay@gmail.com
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files:
|
63
|
+
- LICENSE.txt
|
64
|
+
- README.md
|
65
|
+
- README.rdoc
|
66
|
+
files:
|
67
|
+
- .document
|
68
|
+
- Gemfile
|
69
|
+
- Gemfile.lock
|
70
|
+
- LICENSE.txt
|
71
|
+
- README.md
|
72
|
+
- README.rdoc
|
73
|
+
- Rakefile
|
74
|
+
- VERSION
|
75
|
+
- lib/conf.rb
|
76
|
+
- lib/mech.rb
|
77
|
+
- lib/mech/compiler.rb
|
78
|
+
- lib/mech/compiler/format.rb
|
79
|
+
- lib/mech/compiler/format/action_script.rb
|
80
|
+
- lib/mech/compiler/format/cl.rb
|
81
|
+
- lib/mech/compiler/format/java_script.rb
|
82
|
+
- lib/mech/compiler/format/ruby.rb
|
83
|
+
- lib/mech/compiler/format/scala.rb
|
84
|
+
- lib/mech/compiler/format/yaml.rb
|
85
|
+
- lib/mech/compiler/tmp/action_script.erb
|
86
|
+
- lib/mech/compiler/tmp/cl.erb.erb
|
87
|
+
- lib/mech/compiler/tmp/java_script.erb
|
88
|
+
- lib/mech/compiler/tmp/ruby.erb.erb
|
89
|
+
- lib/mech/compiler/tmp/scala.erb
|
90
|
+
- lib/mech/compiler/tmp/yaml.erb
|
91
|
+
- lib/mech/config.rb
|
92
|
+
- lib/mech/configurator.rb
|
93
|
+
- lib/mech/path_loader.rb
|
94
|
+
- lib/mech/producer.rb
|
95
|
+
- lib/mech/producer/common.rb
|
96
|
+
- lib/mech/producer/default.rb
|
97
|
+
- lib/src/common.yml
|
98
|
+
- lib/src/env/item.yml
|
99
|
+
- lib/src/env/item/items.yml
|
100
|
+
- lib/src/item.yml
|
101
|
+
- mech.gemspec
|
102
|
+
- test/helper.rb
|
103
|
+
- test/test_mech.rb
|
104
|
+
homepage: http://github.com/realb0t/mech
|
105
|
+
licenses:
|
106
|
+
- MIT
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
113
|
+
requirements:
|
114
|
+
- - ! '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
segments:
|
118
|
+
- 0
|
119
|
+
hash: -803900531
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 1.8.6
|
129
|
+
signing_key:
|
130
|
+
specification_version: 3
|
131
|
+
summary: Build config formats from nested yaml
|
132
|
+
test_files: []
|