alki 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.adoc +108 -6
- data/alki.gemspec +2 -2
- data/bin/alki +17 -0
- data/config/dsls.rb +2 -2
- data/doc/assembly_dsl.adoc +6 -6
- data/exe/alki +275 -0
- data/lib/alki/assembly/builder.rb +113 -0
- data/lib/alki/assembly/executor.rb +127 -0
- data/lib/alki/assembly/handler_base.rb +21 -0
- data/lib/alki/assembly/instance.rb +21 -0
- data/lib/alki/assembly/types/assembly.rb +92 -0
- data/lib/alki/assembly/types/factory.rb +29 -0
- data/lib/alki/assembly/types/func.rb +12 -0
- data/lib/alki/assembly/types/group.rb +39 -0
- data/lib/alki/assembly/types/override.rb +40 -0
- data/lib/alki/assembly/types/proc_value.rb +18 -0
- data/lib/alki/assembly/types/service.rb +27 -0
- data/lib/alki/assembly/types/value.rb +9 -0
- data/lib/alki/assembly.rb +21 -40
- data/lib/alki/dsls/assembly.rb +10 -12
- data/lib/alki/dsls/assembly_group.rb +92 -0
- data/lib/alki/dsls/assembly_type.rb +5 -15
- data/lib/alki/execution/cache_entry.rb +16 -0
- data/lib/alki/execution/context.rb +29 -0
- data/lib/alki/execution/context_class_builder.rb +36 -0
- data/lib/alki/execution/value_context.rb +14 -0
- data/lib/alki/overlay_delegator.rb +8 -20
- data/lib/alki/overlay_info.rb +3 -0
- data/lib/alki/override_builder.rb +6 -4
- data/lib/alki/service_delegator.rb +3 -3
- data/lib/alki/version.rb +1 -1
- data/lib/alki.rb +4 -4
- data/test/feature/alki_test.rb +1 -2
- data/test/feature/example_test.rb +2 -3
- data/test/feature/factories_test.rb +48 -0
- data/test/feature/overlays_test.rb +225 -0
- data/test/feature/overrides_test.rb +1 -2
- data/test/feature/pseudo_elements_test.rb +67 -0
- data/test/feature_test_helper.rb +1 -0
- data/test/fixtures/example/config/assembly.rb +11 -2
- data/test/fixtures/example/config/handlers.rb +2 -7
- data/test/fixtures/example/lib/log_overlay.rb +3 -3
- data/test/integration/dsls/assembly_test.rb +3 -8
- data/test/integration/dsls/assembly_type_test.rb +2 -2
- data/test/integration/dsls/service_dsl_test.rb +2 -2
- metadata +36 -18
- data/lib/alki/assembly_builder.rb +0 -109
- data/lib/alki/assembly_executor.rb +0 -129
- data/lib/alki/assembly_handler_base.rb +0 -19
- data/lib/alki/dsls/assembly_type_dsl.rb +0 -21
- data/lib/alki/dsls/assembly_types/assembly.rb +0 -101
- data/lib/alki/dsls/assembly_types/group.rb +0 -41
- data/lib/alki/dsls/assembly_types/load.rb +0 -31
- data/lib/alki/dsls/assembly_types/overlay.rb +0 -9
- data/lib/alki/dsls/assembly_types/value.rb +0 -100
- data/test/test_helper.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30b3e6d184beebdc00446b13b4930d47d32151df
|
4
|
+
data.tar.gz: 98249b15e58962ab44737b9e54199f8690938407
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df40acd78708b8a0371f5191f1b5160c4d09e9348e92c237791761528a22552f3212c7dd14759c555b20d5364def4cd1976eaa12ad90690d3d9b81a7c5e27670
|
7
|
+
data.tar.gz: 24bc23ef4c32c0b16a6e63a0386c3a767bcc9fc0a2393b8197c9d942e4f9ebad6bc97b394d1d142c060cc39371e42d6fc2edeb6d72a51035fd12dad836babc8c
|
data/README.adoc
CHANGED
@@ -1,12 +1,114 @@
|
|
1
1
|
# What is Alki?
|
2
|
+
:toc:
|
2
3
|
|
3
|
-
Alki is a framework for
|
4
|
+
Alki is a small framework for writing Ruby projects, providing a powerful dependency injection system with
|
5
|
+
helpers for testing, creating executables, and easy to use libraries.
|
4
6
|
|
5
|
-
It's goal is to remove uncertainty and friction when building Ruby projects, allowing developers to focus on
|
7
|
+
It's goal is to remove uncertainty and friction when building Ruby projects, allowing developers to focus on
|
8
|
+
implementing business logic. It can be used alongside other frameworks such as Ruby on Rails.
|
6
9
|
|
7
|
-
|
10
|
+
Alki tries to combine the time tested software engineering concepts such as
|
11
|
+
https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)[SOLID],
|
12
|
+
and https://en.wikipedia.org/wiki/Inversion_of_control[Inversion of Control], with
|
13
|
+
Ruby style ease of use, DSLs, and
|
14
|
+
https://en.wikipedia.org/wiki/Convention_over_configuration[Convention over Configuration].
|
8
15
|
|
9
|
-
|
10
|
-
|
16
|
+
Documentation can be found at https://github.com/alki-project/alki/blob/master/doc/index.adoc
|
17
|
+
|
18
|
+
## Getting Started
|
19
|
+
|
20
|
+
Install from rubygems
|
21
|
+
|
22
|
+
gem install alki
|
23
|
+
|
24
|
+
Setting up Alki in your project requires only created a couple of files, but the
|
25
|
+
`alki` command line tool can also be used to automate the process. Project names
|
26
|
+
should be given in lowercase using underscores and forward slashes as separators.
|
27
|
+
|
28
|
+
.Example project
|
29
|
+
```
|
30
|
+
$ cd <project dir>
|
31
|
+
$ alki init --console <project name>
|
32
|
+
```
|
33
|
+
## Example
|
34
|
+
|
35
|
+
To demonstrate the basic features of Alki, this will go through the creation of
|
36
|
+
a simple example project.
|
37
|
+
|
38
|
+
To get started, a new project should be created.
|
39
|
+
|
40
|
+
```
|
41
|
+
$ mkdir example
|
42
|
+
$ cd example
|
43
|
+
$ alki init --console example
|
44
|
+
```
|
45
|
+
|
46
|
+
### First Service
|
47
|
+
|
48
|
+
Open up `config/assembly.rb` in your favorite text editor and add a simple log
|
49
|
+
service as an example. The service definition should require the files it needs and
|
50
|
+
then construct an object.
|
51
|
+
|
52
|
+
.config/assembly.rb
|
53
|
+
```ruby
|
54
|
+
Alki do
|
55
|
+
mount :console, 'alki/console', name: 'example'
|
56
|
+
|
57
|
+
service :log do
|
58
|
+
require 'logger'
|
59
|
+
Logger.new STDERR
|
60
|
+
end
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
To test, we can open up the console and interact with our new service.
|
65
|
+
|
66
|
+
```bash
|
67
|
+
$ bin/console
|
68
|
+
example> log.info "test message"
|
69
|
+
I, [<timestamp>] INFO -- : test message
|
70
|
+
=> true
|
71
|
+
test> exit
|
72
|
+
```
|
73
|
+
|
74
|
+
### Adding Settings
|
75
|
+
|
76
|
+
Many times in a project there will end with a lot of configuration settings or magic
|
77
|
+
numbers sprinkled throughout your code, maybe pulled from `ENV` or just set directly
|
78
|
+
as constants. Alki provides a simple way to centralize them. By convention this is done
|
79
|
+
by creating a `config/settings.rb` and loading it into your Assembly.
|
80
|
+
|
81
|
+
To demonstrate we can pull the log io (`STDERR`) out of our main assembly and add it
|
82
|
+
to our settings.
|
83
|
+
|
84
|
+
.config/settings.rb
|
85
|
+
```ruby
|
86
|
+
Alki do
|
87
|
+
set :log_io, STDERR
|
88
|
+
end
|
89
|
+
```
|
90
|
+
Now we can load our settings file in our assembly config (`load :settings`) and use
|
91
|
+
the setting in our log service.
|
92
|
+
|
93
|
+
.config/assembly.rb
|
94
|
+
```ruby
|
95
|
+
Alki do
|
96
|
+
load :settings
|
97
|
+
mount :console, 'alki/console', name: 'example'
|
98
|
+
|
99
|
+
service :log do
|
100
|
+
require 'logger'
|
101
|
+
Logger.new settings.log_io
|
102
|
+
end
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
### Adding your own Classes
|
107
|
+
|
108
|
+
Generally, you're not just going to be using other people's classes. Alki doesn't have any requirements as to
|
109
|
+
where your classes need to go, but conventionally they can be placed under `lib/<project-name>/`.
|
110
|
+
|
111
|
+
The Alki style of writing a Class is to only `require` external libraries, or utility files in your class files.
|
112
|
+
All of the "glue" that ties your code together can instead be put in your assembly definition. This allows you
|
113
|
+
to modularize and loosely couple your programs.
|
11
114
|
|
12
|
-
Docs can be found at https://github.com/alki-project/alki/blob/master/doc/index.adoc
|
data/alki.gemspec
CHANGED
@@ -21,6 +21,6 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.6"
|
22
22
|
spec.add_development_dependency "rake", '~> 10.0'
|
23
23
|
spec.add_dependency "minitest", "~> 5.9", '>= 5.9.1'
|
24
|
-
spec.add_dependency "alki-dsl", "~> 0.3", '>= 0.3.
|
25
|
-
spec.add_dependency "alki-support", "~> 0.
|
24
|
+
spec.add_dependency "alki-dsl", "~> 0.3", '>= 0.3.3'
|
25
|
+
spec.add_dependency "alki-support", "~> 0.6"
|
26
26
|
end
|
data/bin/alki
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'alki' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "pathname"
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "bundler/setup"
|
16
|
+
|
17
|
+
load Gem.bin_path("alki", "alki")
|
data/config/dsls.rb
CHANGED
data/doc/assembly_dsl.adoc
CHANGED
@@ -227,7 +227,7 @@ assembly = Alki.create_assembly do
|
|
227
227
|
Logger.new STDOUT
|
228
228
|
end
|
229
229
|
end
|
230
|
-
assembly.new.logger << "hello"
|
230
|
+
assembly.new.logger << "hello\n"
|
231
231
|
|
232
232
|
#output: hello
|
233
233
|
```
|
@@ -251,7 +251,7 @@ assembly = Alki.create_assembly do
|
|
251
251
|
logger STDOUT
|
252
252
|
end
|
253
253
|
end
|
254
|
-
assembly.new.main_logger << "hello"
|
254
|
+
assembly.new.main_logger << "hello\n"
|
255
255
|
|
256
256
|
#output: hello
|
257
257
|
```
|
@@ -265,9 +265,9 @@ Overlays are often most useful in groups where all services adhere to a common i
|
|
265
265
|
can be used to perform aspect oriented programming like logging, validation, or access controls.
|
266
266
|
|
267
267
|
|
268
|
-
## Assemblies (
|
268
|
+
## Mounting Assemblies (mount)
|
269
269
|
|
270
|
-
Other assemblies can be mounted into your Assembly using the `
|
270
|
+
Other assemblies can be mounted into your Assembly using the `mount` command.
|
271
271
|
|
272
272
|
The first argument is what the element should be named in the parent assembly. The optional second argument
|
273
273
|
is the name of the assembly to be mounted. This should be formatted like a require string (relative path but
|
@@ -296,7 +296,7 @@ end
|
|
296
296
|
Alki.create_assembly name: 'main_assembly' do
|
297
297
|
set :val2, "two"
|
298
298
|
# Mounts OtherAssembly as 'other'
|
299
|
-
|
299
|
+
mount :other, 'other_assembly'
|
300
300
|
end
|
301
301
|
instance = MainAssembly.new
|
302
302
|
puts instance.other.val
|
@@ -331,7 +331,7 @@ end
|
|
331
331
|
|
332
332
|
Alki.create_assembly name: 'main_assembly' do
|
333
333
|
set :val, "hello"
|
334
|
-
|
334
|
+
mount :other, 'other_assembly' do
|
335
335
|
set :msg do
|
336
336
|
val
|
337
337
|
end
|
data/exe/alki
ADDED
@@ -0,0 +1,275 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'fileutils'
|
3
|
+
require 'optparse'
|
4
|
+
require 'alki/support'
|
5
|
+
|
6
|
+
valid_addons = ["console"]
|
7
|
+
|
8
|
+
options = {
|
9
|
+
config_dir: nil,
|
10
|
+
primary_config: nil,
|
11
|
+
addons: [],
|
12
|
+
project_dir: Dir.pwd,
|
13
|
+
}
|
14
|
+
parser = OptionParser.new do |opts|
|
15
|
+
opts.banner = "Usage: alki init PROJECT_NAME [options]"
|
16
|
+
|
17
|
+
opts.on("-a", "--add[=ADDON]", "Add addon to project. Valid addons: #{valid_addons.join(', ')}") do |v|
|
18
|
+
unless valid_addons.include? v
|
19
|
+
puts "Invalid addon: #{v}"
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
options[:addon] |= [v]
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on('-d','--directory=DIRECTORY', 'Project root, defaults to the current working directory') do |v|
|
26
|
+
options[:project_dir] = v
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on("-c", "--config=DIECTORY", "Override config dir (default \"config\")") do |v|
|
30
|
+
options[:config_dir] = v
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on("-p", "--primary=PRIMARY_CONFIG", "Override primary config (default \"assembly\")") do |v|
|
34
|
+
options[:primary_config] = v
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
parser.parse!
|
39
|
+
|
40
|
+
if ARGV.size != 2 || ARGV[0] != "init"
|
41
|
+
puts parser.banner
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
|
45
|
+
unless ARGV[1] =~ %r{^[a-z0-9_]+(/[a-z0-9_]+)*$}
|
46
|
+
puts "Invalid project name. May only consist of lowercase letters, numbers, underscores, and forward slashes"
|
47
|
+
exit 1
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
class AlkiFileWriter
|
53
|
+
def initialize(root_dir)
|
54
|
+
@root_dir = root_dir
|
55
|
+
@changes = []
|
56
|
+
@triggers = []
|
57
|
+
end
|
58
|
+
|
59
|
+
def create(file,contents)
|
60
|
+
@changes << [:create,file: file,contents: contents,opts: {}]
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_exec(file,contents)
|
64
|
+
@changes << [:create,file: file,contents: contents,opts: {exec: true}]
|
65
|
+
end
|
66
|
+
|
67
|
+
def check_create(file:, contents:, opts:)
|
68
|
+
path = abs_path( file)
|
69
|
+
if File.exists? path
|
70
|
+
if File.read(path) == contents
|
71
|
+
:skip
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def desc_create(file:, contents:, opts: {})
|
77
|
+
path = abs_path( file)
|
78
|
+
if opts[:exec]
|
79
|
+
adj = "executable "
|
80
|
+
end
|
81
|
+
if File.exists? path
|
82
|
+
"Overwriting #{adj}#{file}!"
|
83
|
+
else
|
84
|
+
"Create #{adj}#{file}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def do_create(file:, contents:, opts: {})
|
89
|
+
path = abs_path( file)
|
90
|
+
FileUtils.mkdir_p File.dirname(path)
|
91
|
+
File.write path, contents
|
92
|
+
FileUtils.chmod '+x', path if opts[:exec]
|
93
|
+
end
|
94
|
+
|
95
|
+
def opt_create(file,contents)
|
96
|
+
@changes << [:opt_create,file: file,contents: contents]
|
97
|
+
end
|
98
|
+
|
99
|
+
def check_opt_create(file:, contents:)
|
100
|
+
if File.exists? abs_path( file)
|
101
|
+
:skip
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def desc_opt_create(opts)
|
106
|
+
desc_create opts
|
107
|
+
end
|
108
|
+
|
109
|
+
def do_opt_create(opts)
|
110
|
+
do_create opts
|
111
|
+
end
|
112
|
+
|
113
|
+
def add_line(file,line,opts={})
|
114
|
+
@changes << [:add_line,file: file,line: line,opts: opts]
|
115
|
+
end
|
116
|
+
|
117
|
+
def check_add_line(file:,line:,opts:)
|
118
|
+
if File.exists? abs_path(file)
|
119
|
+
File.open(file) do |f|
|
120
|
+
if opts[:after]
|
121
|
+
found = until f.eof?
|
122
|
+
break true if f.readline.chomp == opts[:after]
|
123
|
+
end
|
124
|
+
unless found
|
125
|
+
puts "File \"#{file}\" doesn't contain required line #{opts[:after]}"
|
126
|
+
return :abort
|
127
|
+
end
|
128
|
+
end
|
129
|
+
until f.eof?
|
130
|
+
l = f.readline
|
131
|
+
if opts[:match] ? l.chomp.match(opts[:match]) : (l.chomp == line)
|
132
|
+
return :skip
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
else
|
137
|
+
unless @changes.find {|c| [:create,:opt_create].include?(c[0]) && c[1][:file] == file}
|
138
|
+
puts "File \"#{file}\" doesn't exist!"
|
139
|
+
return :abort
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def desc_add_line(file:,line:,opts:)
|
145
|
+
"Add line \"#{line}\" to #{file}"
|
146
|
+
end
|
147
|
+
|
148
|
+
def do_add_line(file:,line:,opts:)
|
149
|
+
if opts[:after]
|
150
|
+
File.write file, File.read(file).sub(/^#{Regexp.quote(opts[:after])}\n/){|m| m + line + "\n"}
|
151
|
+
else
|
152
|
+
File.open(file,'a') do |f|
|
153
|
+
f.puts line
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def trigger(file,cmd)
|
159
|
+
@triggers << [file, cmd]
|
160
|
+
end
|
161
|
+
|
162
|
+
def check_trigger(changes,file)
|
163
|
+
changes.find {|c| c[1][:file] == file}
|
164
|
+
end
|
165
|
+
|
166
|
+
def desc_trigger(cmd:)
|
167
|
+
"Run \"#{cmd}\""
|
168
|
+
end
|
169
|
+
|
170
|
+
def do_trigger(cmd:)
|
171
|
+
system cmd
|
172
|
+
end
|
173
|
+
|
174
|
+
def check_changes
|
175
|
+
puts "Checking preconditions..."
|
176
|
+
abort = false
|
177
|
+
unless Dir.exists?(@root_dir)
|
178
|
+
puts "Root dir doesn't exist"
|
179
|
+
exit 1
|
180
|
+
end
|
181
|
+
do_changes = []
|
182
|
+
@changes.each do |(type,args)|
|
183
|
+
res = send "check_#{type}", args
|
184
|
+
abort = true if res == :abort
|
185
|
+
do_changes << [type,args] unless res == :skip
|
186
|
+
end
|
187
|
+
@triggers.each do |(file,cmd)|
|
188
|
+
if check_trigger do_changes, file
|
189
|
+
do_changes << [:trigger,cmd: cmd]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
exit 1 if abort
|
193
|
+
do_changes
|
194
|
+
end
|
195
|
+
|
196
|
+
def print_overview(changes)
|
197
|
+
puts "Overview of changes to be made:"
|
198
|
+
|
199
|
+
changes.each do |(type,args)|
|
200
|
+
desc = send "desc_#{type}", args
|
201
|
+
puts " #{desc}" if desc
|
202
|
+
end
|
203
|
+
print "Proceed? "
|
204
|
+
resp = STDIN.gets.chomp
|
205
|
+
unless resp =~ /^y(es?)?/i
|
206
|
+
puts "Aborting"
|
207
|
+
exit
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def write
|
212
|
+
puts "Using project root: #{@root_dir}\n"
|
213
|
+
do_changes = check_changes
|
214
|
+
print_overview do_changes
|
215
|
+
|
216
|
+
puts "Writing changes..."
|
217
|
+
do_changes.each do |(type,args)|
|
218
|
+
send "do_#{type}", args
|
219
|
+
end
|
220
|
+
puts "Done"
|
221
|
+
end
|
222
|
+
|
223
|
+
def abs_path(p)
|
224
|
+
File.expand_path(p,@root_dir)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
project_name = ARGV[1]
|
229
|
+
|
230
|
+
fw = AlkiFileWriter.new config[:project_dir]
|
231
|
+
|
232
|
+
config_dir = options[:config_dir] || 'config'
|
233
|
+
primary_config = options[:primary_config] || 'assembly'
|
234
|
+
primary_config_path = File.join(config_dir,primary_config+'.rb')
|
235
|
+
fw.opt_create primary_config_path, <<END
|
236
|
+
Alki do
|
237
|
+
# Assembly config goes here
|
238
|
+
end
|
239
|
+
END
|
240
|
+
|
241
|
+
opts = []
|
242
|
+
opts << "config_dir: '#{options[:config_dir]}'" if options[:config_dir]
|
243
|
+
opts << "primary_config: '#{options[:primary_config]}'" if options[:primary_config]
|
244
|
+
unless opts.empty?
|
245
|
+
opt_str = " #{opts.join(', ')}"
|
246
|
+
end
|
247
|
+
fw.create "lib/#{project_name}.rb", <<END
|
248
|
+
require 'alki'
|
249
|
+
Alki.project_assembly!#{opt_str}
|
250
|
+
END
|
251
|
+
|
252
|
+
fw.opt_create "Gemfile", <<END
|
253
|
+
source "https://rubygems.org"
|
254
|
+
END
|
255
|
+
|
256
|
+
fw.trigger 'Gemfile', 'bundle install'
|
257
|
+
|
258
|
+
fw.add_line "Gemfile", "gem 'alki'", match: /^gem ['"]alki['"]/
|
259
|
+
|
260
|
+
if options[:addons].include? "console"
|
261
|
+
fw.add_line "Gemfile", "gem 'alki-console'", match: /^gem ['"]alki-console['"]/
|
262
|
+
|
263
|
+
name = project_name.tr('/','-')
|
264
|
+
fw.add_line primary_config_path, " mount :console, 'alki/console', name: '#{name}'", match: /^\s*assembly :console/, after: 'Alki do'
|
265
|
+
|
266
|
+
fw.create_exec 'bin/console', <<END
|
267
|
+
#!/usr/bin/env ruby
|
268
|
+
require 'bundler/setup'
|
269
|
+
require 'alki/bin'
|
270
|
+
require '#{project_name}'
|
271
|
+
#{Alki::Support.classify(project_name)}.new.console.run
|
272
|
+
END
|
273
|
+
end
|
274
|
+
|
275
|
+
fw.write
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'alki/assembly'
|
2
|
+
require 'alki/class_builder'
|
3
|
+
require 'alki/dsl'
|
4
|
+
require 'alki/support'
|
5
|
+
|
6
|
+
module Alki
|
7
|
+
module Assembly
|
8
|
+
class Builder
|
9
|
+
def initialize
|
10
|
+
@config_dir = nil
|
11
|
+
@assembly_name = nil
|
12
|
+
@definition = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :config_dir, :assembly_name, :definition
|
16
|
+
|
17
|
+
def self.build(opts={},&blk)
|
18
|
+
new.build(opts,&blk)
|
19
|
+
end
|
20
|
+
|
21
|
+
def build(opts={},&blk)
|
22
|
+
build_assembly blk if blk
|
23
|
+
if opts[:config_dir]
|
24
|
+
context = if opts[:project_assembly]
|
25
|
+
File.dirname opts[:project_assembly]
|
26
|
+
else
|
27
|
+
Dir.pwd
|
28
|
+
end
|
29
|
+
@config_dir = File.expand_path opts[:config_dir], context
|
30
|
+
end
|
31
|
+
set_assembly_name opts[:name] if opts[:name]
|
32
|
+
setup_project_assembly opts[:project_assembly] if opts[:project_assembly]
|
33
|
+
register_config_directory if @config_dir
|
34
|
+
if blk
|
35
|
+
build_assembly blk
|
36
|
+
else
|
37
|
+
load_assembly_file opts[:primary_config]
|
38
|
+
end
|
39
|
+
build_empty_assembly unless definition
|
40
|
+
build_class
|
41
|
+
end
|
42
|
+
|
43
|
+
def setup_project_assembly(path)
|
44
|
+
root = Alki::Support.find_root(path) do |dir|
|
45
|
+
File.exists?(File.join(dir,'config','assembly.rb')) ||
|
46
|
+
File.exists?(File.join(dir,'Gemfile')) ||
|
47
|
+
!Dir.glob(File.join(dir,'*.gemspec')).empty?
|
48
|
+
end
|
49
|
+
if root
|
50
|
+
unless @config_dir
|
51
|
+
config_dir = File.join(root,'config')
|
52
|
+
@config_dir = config_dir if File.exists? config_dir
|
53
|
+
end
|
54
|
+
|
55
|
+
unless @assembly_name
|
56
|
+
lib_dir = File.join(root,'lib')
|
57
|
+
name = Alki::Support.path_name path, lib_dir
|
58
|
+
unless name
|
59
|
+
raise "Can't auto-detect name of assembly"
|
60
|
+
end
|
61
|
+
set_assembly_name name
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def set_assembly_name(name)
|
67
|
+
@assembly_name = name
|
68
|
+
end
|
69
|
+
|
70
|
+
def register_config_directory
|
71
|
+
opts = {config_dir: @config_dir}
|
72
|
+
opts[:prefix] = File.join(@assembly_name,'alki_config') if @assembly_name
|
73
|
+
Alki::Dsl.register_dir @config_dir, 'alki/dsls/assembly', opts
|
74
|
+
end
|
75
|
+
|
76
|
+
def load_assembly_file(name = nil)
|
77
|
+
name ||= 'assembly'
|
78
|
+
if @config_dir
|
79
|
+
assembly_config_path = File.join(@config_dir,"#{name}.rb")
|
80
|
+
if File.exists? assembly_config_path
|
81
|
+
@definition = Alki::Dsl.load(assembly_config_path)[:class]
|
82
|
+
true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def build_empty_assembly
|
88
|
+
build_assembly ->{}
|
89
|
+
end
|
90
|
+
|
91
|
+
def build_assembly(blk)
|
92
|
+
@definition = Alki::Dsl.build('alki/dsls/assembly', config_dir: @config_dir, &blk)[:class]
|
93
|
+
end
|
94
|
+
|
95
|
+
def build_class
|
96
|
+
definition = @definition
|
97
|
+
Alki::ClassBuilder.build(
|
98
|
+
prefix: '',
|
99
|
+
name: @assembly_name,
|
100
|
+
class_modules: [Alki::Assembly],
|
101
|
+
type: :module,
|
102
|
+
class_methods: {
|
103
|
+
definition: {
|
104
|
+
body: ->{
|
105
|
+
definition
|
106
|
+
}
|
107
|
+
},
|
108
|
+
}
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|