disco-railties 0.5.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +1 -0
- data/bin/disco +7 -0
- data/bin/drails +3 -0
- data/lib/disco/app_disco_loader.rb +62 -0
- data/lib/disco/cli.rb +11 -0
- data/lib/disco/commands/application.rb +43 -0
- data/lib/disco/commands/destroy.rb +12 -0
- data/lib/disco/commands/domainserver.rb +6 -0
- data/lib/disco/commands/generate.rb +12 -0
- data/lib/disco/commands/projectionserver.rb +9 -0
- data/lib/disco/commands/server.rb +22 -0
- data/lib/disco/commands.rb +70 -0
- data/lib/disco/generators.rb +48 -0
- data/lib/disco/server/domain_server.rb +26 -0
- data/lib/disco/server/projection_servers.rb +26 -0
- data/lib/generators/disco/app/USAGE +14 -0
- data/lib/generators/disco/app/app_generator.rb +140 -0
- data/lib/generators/disco/app/templates/app/controllers/event_source_controller.rb +16 -0
- data/lib/generators/disco/app/templates/bin/disco +3 -0
- data/lib/generators/disco/app/templates/config/disco.yml +27 -0
- data/lib/generators/disco/app/templates/config/initializers/build_validations_registry.rb +19 -0
- data/lib/generators/disco/app/templates/config/initializers/create_domain.rb +5 -0
- data/lib/generators/disco/app/templates/db/seeds.rb +14 -0
- data/lib/generators/disco/command/USAGE +11 -0
- data/lib/generators/disco/command/command_generator.rb +69 -0
- data/lib/generators/disco/command/templates/command.rb.erb +24 -0
- data/lib/generators/disco/command/templates/event.rb.erb +11 -0
- data/lib/generators/disco/command_processor/USAGE +1 -0
- data/lib/generators/disco/command_processor/command_processor_generator.rb +22 -0
- data/lib/generators/disco/command_processor/templates/command_processor.rb +5 -0
- data/lib/generators/disco/domain.rb +19 -0
- data/lib/generators/disco/event_name.rb +52 -0
- data/lib/generators/disco/migration/USAGE +41 -0
- data/lib/generators/disco/migration/migration_generator.rb +27 -0
- data/lib/generators/disco/migration/templates/create_table_migration.rb +19 -0
- data/lib/generators/disco/model/USAGE +17 -0
- data/lib/generators/disco/model/model_generator.rb +29 -0
- data/lib/generators/disco/model/templates/domain_model.rb +5 -0
- data/lib/generators/disco/model/templates/model.rb +5 -0
- data/lib/generators/disco/processor_name.rb +48 -0
- data/lib/generators/disco/projection/USAGE +13 -0
- data/lib/generators/disco/projection/projection_generator.rb +19 -0
- data/lib/generators/disco/projection/templates/domain_projection.rb +9 -0
- data/lib/generators/disco/projection/templates/domain_projection_test.rb +6 -0
- data/lib/generators/disco/projection/templates/projection.rb +9 -0
- data/lib/generators/disco/projection/templates/projection_test.rb +6 -0
- data/lib/generators/disco/scaffold/USAGE +27 -0
- data/lib/generators/disco/scaffold/scaffold_generator.rb +91 -0
- data/lib/generators/disco/scaffold/templates/_eventstream.js.erb +16 -0
- data/lib/generators/disco/scaffold_controller/USAGE +1 -0
- data/lib/generators/disco/scaffold_controller/scaffold_controller_generator.rb +27 -0
- data/lib/generators/disco/scaffold_controller/templates/controller.rb +68 -0
- data/lib/generators/disco/scaffold_controller/templates/controller_test.rb +45 -0
- data/lib/generators/disco/use_domain_option.rb +54 -0
- data/lib/rails-disco/railtie.rb +8 -0
- data/lib/rails-disco/tasks.rb +1 -0
- data/lib/rails-disco/version.rb +10 -0
- data/lib/tasks/db.rake +222 -0
- data/lib/tasks/split.rake +94 -0
- metadata +161 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'generators/disco/processor_name.rb'
|
2
|
+
require 'generators/disco/event_name.rb'
|
3
|
+
require 'generators/disco/domain.rb'
|
4
|
+
|
5
|
+
module Disco
|
6
|
+
module Generators
|
7
|
+
class CommandGenerator < Rails::Generators::NamedBase
|
8
|
+
source_root File.expand_path('../templates', __FILE__)
|
9
|
+
argument :attributes, type: :array, default: [], banner: 'attribute attribute'
|
10
|
+
class_option :skip_model, type: :boolean, default: false, desc: 'Skip active model from the command'
|
11
|
+
class_option :model_name, type: :string, desc: 'Name of the active model behind the command'
|
12
|
+
class_option :persisted, type: :boolean, default: false, desc: 'Does the command update an existing model'
|
13
|
+
include ProcessorName
|
14
|
+
include EventName
|
15
|
+
include Domain
|
16
|
+
|
17
|
+
def create_command_file
|
18
|
+
template 'command.rb.erb', File.join('app/commands', class_path, "#{file_name}_command.rb")
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_related_event_file
|
22
|
+
return if skip_event?
|
23
|
+
raise 'do not use id as attribute, this is reserved for the event id itself' if attributes_names.include? 'id'
|
24
|
+
template 'event.rb.erb', File.join('app/events', event_class_path, "#{event_file_name}_event.rb")
|
25
|
+
end
|
26
|
+
|
27
|
+
hook_for :command_processor, require: true do |hook|
|
28
|
+
unless skip_processor?
|
29
|
+
invoke hook, [processor_file_path], %w(-s --skip-namespace)
|
30
|
+
add_to_command_processor
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def add_to_command_processor
|
37
|
+
return if skip_processor? || (behavior == :revoke)
|
38
|
+
content = "
|
39
|
+
|
40
|
+
process #{class_name}Command do |command|
|
41
|
+
command.is_valid_do { event #{event_class_name}Event.new command.to_hash }
|
42
|
+
end"
|
43
|
+
file = File.join('domain/command_processors', processor_domain_class_path, "#{processor_file_name}_processor.rb")
|
44
|
+
inject_into_file file, content, after: /(\s)*include(\s)*ActiveDomain::CommandProcessor/
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def skip_model?
|
50
|
+
options[:skip_model]
|
51
|
+
end
|
52
|
+
|
53
|
+
def model_name
|
54
|
+
options[:model_name]
|
55
|
+
end
|
56
|
+
|
57
|
+
def persisted?
|
58
|
+
options[:persisted]
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# allow this generator to be called multiple times
|
64
|
+
def invoke_command(command, *args) #:nodoc:
|
65
|
+
command.run(self, *args)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<% module_namespacing do -%>
|
2
|
+
class <%= class_name %>Command
|
3
|
+
<%- unless skip_model? -%>
|
4
|
+
include ActiveModel::Model
|
5
|
+
<%- end -%>
|
6
|
+
include ActiveEvent::Command
|
7
|
+
attributes <%= (['id'] + attributes_names).map{|x| ":#{x}"}.join(', ') %>
|
8
|
+
<%- if !model_name.blank? && !skip_model? -%>
|
9
|
+
|
10
|
+
def self.model_name
|
11
|
+
@_model_name ||= begin
|
12
|
+
namespace = self.parents.detect do |n|
|
13
|
+
n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
|
14
|
+
end
|
15
|
+
ActiveModel::Name.new(self, namespace, <%= model_name.inspect %>)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
<%- end -%>
|
19
|
+
<%- if persisted? && ! skip_model? -%>
|
20
|
+
|
21
|
+
def persisted?; true end
|
22
|
+
<%- end -%>
|
23
|
+
end
|
24
|
+
<% end -%>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% module_namespacing do -%>
|
2
|
+
class <%= event_class_name %>Event
|
3
|
+
include ActiveEvent::EventType
|
4
|
+
attributes <%= (['id'] + attributes_names).map{|x| ":#{x}"}.join(', ') %>
|
5
|
+
<%- unless attributes_names.empty? -%>
|
6
|
+
def values
|
7
|
+
attributes_except :id
|
8
|
+
end
|
9
|
+
<%- end -%>
|
10
|
+
end
|
11
|
+
<% end -%>
|
@@ -0,0 +1 @@
|
|
1
|
+
Not intended for extern use!
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'generators/disco/domain.rb'
|
2
|
+
|
3
|
+
module Disco
|
4
|
+
module Generators
|
5
|
+
class CommandProcessorGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
include Domain
|
8
|
+
hide!
|
9
|
+
|
10
|
+
def create_command_processor_file
|
11
|
+
template 'command_processor.rb', File.join('domain/command_processors', domain_class_path, "#{file_name}_processor.rb")
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# allow this generator to be called multiple times
|
17
|
+
def invoke_command(command, *args) #:nodoc:
|
18
|
+
command.run(self, *args)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Disco
|
4
|
+
module Generators
|
5
|
+
module Domain
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
def domain_class_path
|
9
|
+
@domain_calss_path ||= class_path_domain class_path
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def class_path_domain(class_path)
|
15
|
+
(Array.new class_path).unshift 'domain'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Disco
|
4
|
+
module Generators
|
5
|
+
module EventName
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
class_option :event, type: :string, default: nil, desc: "name of the event (defaults to NAME)"
|
10
|
+
class_option :skip_event, type: :boolean, default: false, desc: "skip event generation"
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(args, *options)
|
14
|
+
super
|
15
|
+
assign_event_name!(event_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
attr_reader :event_file_name
|
21
|
+
attr_reader :event_class_path
|
22
|
+
|
23
|
+
def skip_event?
|
24
|
+
options[:skip_event]
|
25
|
+
end
|
26
|
+
|
27
|
+
def event_name
|
28
|
+
options[:event] || name
|
29
|
+
end
|
30
|
+
|
31
|
+
def event_class_name
|
32
|
+
(event_class_path + [event_file_name]).map!{ |m| m.camelize }.join('::')
|
33
|
+
end
|
34
|
+
|
35
|
+
def event_file_path
|
36
|
+
@event_file_path ||= (event_class_path + [event_file_name]).join('/')
|
37
|
+
end
|
38
|
+
|
39
|
+
def event_domain_class_path
|
40
|
+
@event_domain_class_path ||= class_path_domain event_class_path
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def assign_event_name!(event_name)
|
46
|
+
@event_class_path = event_name.include?('/') ? event_name.split('/') : event_name.split('::')
|
47
|
+
@event_class_path.map! &:underscore
|
48
|
+
@event_file_name = @event_class_path.pop
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
Description:
|
2
|
+
Stubs out a new database migration for ActiveRecord. Pass the migration name, either
|
3
|
+
CamelCased or under_scored, and an optional list of attribute pairs as arguments.
|
4
|
+
|
5
|
+
A migration class is generated in db/migrate prefixed by a timestamp of the current date and time.
|
6
|
+
|
7
|
+
You can name your migration in either of these formats to generate add/remove
|
8
|
+
column lines from supplied attributes: AddColumnsToTable or RemoveColumnsFromTable
|
9
|
+
|
10
|
+
Example:
|
11
|
+
`disco generate migration AddSslFlag`
|
12
|
+
|
13
|
+
If the current date is May 14, 2008 and the current time 09:09:12, this creates the AddSslFlag migration
|
14
|
+
db/migrate/20080514090912_add_ssl_flag.rb
|
15
|
+
|
16
|
+
`disco generate migration AddSslFlag --domain`
|
17
|
+
|
18
|
+
Under the same conditions as above, this creates the AddSslFlag migration
|
19
|
+
db/migrate_domain/20080514090912_add_ssl_flag.rb
|
20
|
+
|
21
|
+
`disco generate migration AddTitleBodyToPost title:string body:text published:boolean`
|
22
|
+
|
23
|
+
This will create the AddTitleBodyToPost in db/migrate/20080514090912_add_title_body_to_post.rb with this in the Change migration:
|
24
|
+
|
25
|
+
add_column :posts, :title, :string
|
26
|
+
add_column :posts, :body, :text
|
27
|
+
add_column :posts, :published, :boolean
|
28
|
+
|
29
|
+
Migration names containing JoinTable will generate join tables for use with
|
30
|
+
has_and_belongs_to_many associations.
|
31
|
+
|
32
|
+
Example:
|
33
|
+
`disco g migration CreateMediaJoinTable artists musics:uniq`
|
34
|
+
|
35
|
+
will create the migration
|
36
|
+
|
37
|
+
create_join_table :artists, :musics do |t|
|
38
|
+
# t.index [:artist_id, :music_id]
|
39
|
+
t.index [:music_id, :artist_id], unique: true
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rails/generators/active_record/migration/migration_generator'
|
2
|
+
require 'generators/disco/use_domain_option.rb'
|
3
|
+
|
4
|
+
module Disco
|
5
|
+
module Generators
|
6
|
+
class MigrationGenerator < ActiveRecord::Generators::MigrationGenerator
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
include UseDomainOption
|
9
|
+
|
10
|
+
def create_migration_file
|
11
|
+
set_local_assigns!
|
12
|
+
validate_file_name!
|
13
|
+
migration_template @migration_template, "db/#{migration_dir}/#{file_name}.rb"
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def migration_dir
|
19
|
+
if use_domain?
|
20
|
+
'migrate_domain'
|
21
|
+
else
|
22
|
+
'migrate'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :<%= table_name %> do |t|
|
4
|
+
<% attributes.each do |attribute| -%>
|
5
|
+
<% if attribute.password_digest? -%>
|
6
|
+
t.string :password_digest<%= attribute.inject_options %>
|
7
|
+
<% else -%>
|
8
|
+
t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
|
9
|
+
<% end -%>
|
10
|
+
<% end -%>
|
11
|
+
<% if options[:timestamps] %>
|
12
|
+
t.timestamps
|
13
|
+
<% end -%>
|
14
|
+
end
|
15
|
+
<% attributes_with_index.each do |attribute| -%>
|
16
|
+
add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
|
17
|
+
<% end -%>
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Description:
|
2
|
+
Generates a Model and a Projection for it.
|
3
|
+
|
4
|
+
Example:
|
5
|
+
disco generate model Thing [attr1:type, attr2:type]
|
6
|
+
|
7
|
+
This will create:
|
8
|
+
app/projection/thing_projection.rb
|
9
|
+
app/models/thing.rb
|
10
|
+
db/migrate/create_thing.rb
|
11
|
+
|
12
|
+
disco generate model Thing [attr1:type, attr2:type] --domain
|
13
|
+
|
14
|
+
This will create:
|
15
|
+
domain/projections/domain/thing_projection.rb
|
16
|
+
domain/models/domain/thing.rb
|
17
|
+
db/migrate_domain/create_thing.rb
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'generators/disco/use_domain_option.rb'
|
2
|
+
|
3
|
+
module Disco
|
4
|
+
module Generators
|
5
|
+
class ModelGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
argument :attributes, type: :array, default: [], banner: 'field[:type] field[:type]'
|
8
|
+
include UseDomainOption
|
9
|
+
|
10
|
+
hook_for :projection, require: true do |hook|
|
11
|
+
invoke hook, [name]
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_model_file
|
15
|
+
template use_domain('model.rb'), use_domain_class_file_path('models', "#{file_name}.rb")
|
16
|
+
end
|
17
|
+
|
18
|
+
hook_for :migration, require: true do |hook|
|
19
|
+
invoke hook, ["create_#{table_name}", *attributes]
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# do not parse - keep attributes for forwarding to migration
|
25
|
+
def parse_attributes!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Disco
|
4
|
+
module Generators
|
5
|
+
module ProcessorName
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
class_option :processor, type: :string, default: nil, desc: "class_name of the command processor (defaults to NAME)"
|
10
|
+
class_option :skip_processor, type: :boolean, default: false, desc: "Skip command processor generation"
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(args, *options)
|
14
|
+
super
|
15
|
+
assign_processor_names!(processor_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
attr_reader :processor_file_name
|
21
|
+
attr_reader :processor_class_path
|
22
|
+
|
23
|
+
def skip_processor?
|
24
|
+
options[:skip_processor]
|
25
|
+
end
|
26
|
+
|
27
|
+
def processor_name
|
28
|
+
options[:processor] || name
|
29
|
+
end
|
30
|
+
|
31
|
+
def processor_file_path
|
32
|
+
@processor_file_path ||= (processor_class_path + [processor_file_name]).join('/')
|
33
|
+
end
|
34
|
+
|
35
|
+
def processor_domain_class_path
|
36
|
+
@processor_domain_class_path ||= class_path_domain processor_class_path
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def assign_processor_names!(processor_name)
|
42
|
+
@processor_class_path = processor_name.include?('/') ? processor_name.split('/') : processor_name.split('::')
|
43
|
+
@processor_class_path.map! &:underscore
|
44
|
+
@processor_file_name = @processor_class_path.pop
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Description:
|
2
|
+
Generates a projection with handlers for the given events.
|
3
|
+
|
4
|
+
Example:
|
5
|
+
disco generate projection Thing [event event]
|
6
|
+
|
7
|
+
This will create:
|
8
|
+
app/projection/thing_projection.rb
|
9
|
+
|
10
|
+
disco generate projection Thing [event event] --domain
|
11
|
+
|
12
|
+
This will create:
|
13
|
+
domain/projections/domain/thing_projection.rb
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'generators/disco/use_domain_option.rb'
|
2
|
+
|
3
|
+
module Disco
|
4
|
+
module Generators
|
5
|
+
class ProjectionGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
argument :events, type: :array, default: [], banner: 'event event'
|
8
|
+
include UseDomainOption
|
9
|
+
|
10
|
+
def create_projection_file
|
11
|
+
template use_domain('projection.rb'), use_domain_class_file_path('projections', "#{plural_file_name}_projection.rb")
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_test_files
|
15
|
+
template use_domain('projection_test.rb'), File.join('test/projections', use_domain_class_path, "#{plural_file_name}_projection_test.rb")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module <%= Rails::Generators.namespace.name if Rails::Generators.namespace.present? %>Domain
|
2
|
+
class <%= class_name %>Projection
|
3
|
+
include ActiveDomain::Projection
|
4
|
+
<% events.each do |event| %>
|
5
|
+
def <%= event.underscore.split('/') * '__' %>(event)
|
6
|
+
end
|
7
|
+
<% end %>
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Description:
|
2
|
+
Scaffolds a complete resource with models, migration, projections, controller, views
|
3
|
+
commands, events and command_processor.
|
4
|
+
|
5
|
+
Example:
|
6
|
+
disco generate scaffold Thing [attr1:type, attr2:type]
|
7
|
+
|
8
|
+
This will create:
|
9
|
+
app/controllers/things_controller
|
10
|
+
app/commands/create_thing_command.rb
|
11
|
+
app/commands/update_thing_command.rb
|
12
|
+
app/commands/delete_thing_command.rb
|
13
|
+
domain/command_processors/thing_processor.rb
|
14
|
+
app/events/created_thing_event.rb
|
15
|
+
app/events/updated_thing_event.rb
|
16
|
+
app/events/deleted_thing_event.rb
|
17
|
+
app/projections/things_projection.rb
|
18
|
+
db/migrate/create_things.rb
|
19
|
+
app/models/thing.rb
|
20
|
+
app/helpers/things_helper.rb
|
21
|
+
app/views/things/_eventstream.js.erb
|
22
|
+
app/views/things/_form.html.erb
|
23
|
+
app/views/things/edit.html.erb
|
24
|
+
app/views/things/index.html.erb
|
25
|
+
app/views/things/new.html.erb
|
26
|
+
app/views/things/show.html.erb
|
27
|
+
a resource route
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'generators/disco/processor_name.rb'
|
2
|
+
require 'generators/disco/domain.rb'
|
3
|
+
|
4
|
+
module Disco
|
5
|
+
module Generators
|
6
|
+
class ScaffoldGenerator < Rails::Generators::NamedBase
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
argument :attributes, type: :array, default: [], banner: 'field[:type] field[:type]'
|
9
|
+
include ProcessorName
|
10
|
+
include Domain
|
11
|
+
|
12
|
+
hook_for :model, in: :disco, require: true
|
13
|
+
|
14
|
+
hook_for :command, in: :disco, require: true do |hook|
|
15
|
+
%w(create update delete).each do |action|
|
16
|
+
args = [(class_path + ["#{action}_#{file_name}"]) * '/']
|
17
|
+
args += attributes_names unless action == 'delete'
|
18
|
+
opts = ["--event=#{(class_path + ["#{action}d_#{file_name}"]) * '/'}"]
|
19
|
+
opts << "--processor=#{processor_name}" unless skip_processor?
|
20
|
+
opts << '--skip_model' if action == 'delete'
|
21
|
+
opts << "--model_name=#{class_name}"
|
22
|
+
opts << '--persisted' if action == 'update'
|
23
|
+
invoke hook, args, opts
|
24
|
+
add_to_projections(action)
|
25
|
+
end
|
26
|
+
add_to_command_processor
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_routes
|
30
|
+
routing_code = ''
|
31
|
+
class_path.each_with_index do |namespace, index|
|
32
|
+
add_line_with_indent routing_code, (index + 1), "namespace :#{namespace} do"
|
33
|
+
end
|
34
|
+
add_line_with_indent routing_code, (class_path.length + 1), "resources :#{plural_name}"
|
35
|
+
class_path.each_with_index do |_, index|
|
36
|
+
add_line_with_indent routing_code, (class_path.length - index), 'end'
|
37
|
+
end
|
38
|
+
route routing_code[2..-1]
|
39
|
+
end
|
40
|
+
|
41
|
+
hook_for :scaffold_controller, in: :disco, require: true do |hook|
|
42
|
+
invoke hook
|
43
|
+
add_event_stream_to_views
|
44
|
+
end
|
45
|
+
|
46
|
+
def copy_event_stream_client
|
47
|
+
# ensure if app was created before this was default
|
48
|
+
copy_file '_eventstream.js.erb', 'app/views/application/eventstream/_eventstream.js.erb', verbose: false, skip: true
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def add_event_stream_to_views
|
54
|
+
return if behavior == :revoke
|
55
|
+
include_text = '<%= javascript_tag render partial: \'application/eventstream/eventstream\', formats: [:js], locals: {event_id: @event_id} %>'
|
56
|
+
prepend_to_file File.join('app/views', class_path, plural_file_name, 'index.html.erb'), include_text
|
57
|
+
prepend_to_file File.join('app/views', class_path, plural_file_name, 'show.html.erb'), include_text
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_to_command_processor
|
61
|
+
return if behavior == :revoke
|
62
|
+
content = "\n command.id = ActiveDomain::UniqueCommandIdRepository.new_for command.class.name"
|
63
|
+
insert_into_file File.join('domain/command_processors', domain_class_path, "#{processor_file_name}_processor.rb"), content, after: /(\s)*process(\s)*(.)*CreateCommand(.)*/
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_to_projections(action)
|
67
|
+
return if behavior == :revoke
|
68
|
+
event_func = (class_path + ["#{action}d_#{file_name}_event"]) * '__'
|
69
|
+
content = "
|
70
|
+
|
71
|
+
def #{event_func}(event)
|
72
|
+
#{method_bodies[action.to_sym]}
|
73
|
+
end"
|
74
|
+
indent(content) if namespaced?
|
75
|
+
inject_into_file File.join('app/projections', class_path, "#{plural_file_name}_projection.rb"), content, after: /(\s)*include(\s)*ActiveProjection::ProjectionType/
|
76
|
+
end
|
77
|
+
|
78
|
+
def method_bodies
|
79
|
+
@method_bodies ||= {
|
80
|
+
create: "#{class_name}.create! event.values.merge(id: event.id)",
|
81
|
+
update: "#{class_name}.find(event.id).update! event.values",
|
82
|
+
delete: "#{class_name}.find(event.id).destroy!",
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_line_with_indent(target, indent, str)
|
87
|
+
target << "#{' ' * indent}#{str}\n"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<% if event_id.present? %>
|
2
|
+
$(document).ready(function () {
|
3
|
+
setTimeout(function () {
|
4
|
+
var source = new EventSource('/event_stream');
|
5
|
+
source.addEventListener('refresh', function (e) {
|
6
|
+
var event = JSON.parse(e.data);
|
7
|
+
if (<%= event_id %> == event.id){
|
8
|
+
window.location.reload();
|
9
|
+
}else if (<%= event_id %> < event.id){
|
10
|
+
source.removeEventListener('refresh');
|
11
|
+
source.close();
|
12
|
+
}
|
13
|
+
});
|
14
|
+
}, 1);
|
15
|
+
});
|
16
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
Not intended for extern use!
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
|
2
|
+
module Disco
|
3
|
+
module Generators
|
4
|
+
class ScaffoldControllerGenerator < Rails::Generators::ScaffoldControllerGenerator
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
6
|
+
hide!
|
7
|
+
|
8
|
+
# the normal test_framework will not cover our usecase
|
9
|
+
remove_hook_for :test_framework
|
10
|
+
def create_test_files
|
11
|
+
template 'controller_test.rb', File.join('test/controllers', controller_class_path, "#{controller_file_name}_controller_test.rb")
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def command_class_name(command)
|
17
|
+
(class_path + ["#{command}_#{file_name}"]).map(&:camelize) * '::'
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def params_string
|
23
|
+
attributes.map { |x| "#{x.name}: params[:#{singular_table_name}][:#{x.name}]" }.join(', ')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|