mushin 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.ssd/eventstream/11_29_2016.ssd +2 -0
- data/.ssd/eventstream/11_30_2016.ssd +9 -0
- data/lib/mushin/bot.rb +236 -0
- data/lib/mushin/cqrs/command.rb +106 -0
- data/lib/mushin/cqrs/query.rb +116 -0
- data/lib/mushin/domain.rb +5 -1
- data/lib/mushin/dsl.rb +1 -0
- data/lib/mushin/dsl_builder.rb +10 -107
- data/lib/mushin/es/event.rb +18 -0
- data/lib/mushin/es/event_stream.rb +33 -0
- data/lib/mushin/test_helper.rb +9 -2
- data/lib/mushin/version.rb +1 -1
- data/lib/mushin.rb +32 -3
- data/mushin.gemspec +7 -0
- data/samples/sample1.rb +55 -7
- metadata +65 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 791ed6577d3d1449a3909a83c6b8908a2034069c
|
4
|
+
data.tar.gz: 67d81b8451b9fa51bb7565eea0234701ef644481
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d4ed1678810aa2faa3906160b968180b7c9df1fa0299a2dd0ef55a952585e6db888fc8500533e0bffad6d1d7f5d8dedd57f19d164cc360f84bf18d6f9774188
|
7
|
+
data.tar.gz: b5c8762676a8d304babf5b82e94109a00efce457d0d8dc39b5c9fbfde40aebdac006230454412244c088727f520010e4c6d85b17f51d27ab514de06e82503e08
|
@@ -0,0 +1,9 @@
|
|
1
|
+
---
|
2
|
+
2016-11-30 08:05:58 UTC_11_30_2016: !ruby/object:Mushin::ES::Event {}
|
3
|
+
2016-11-30 08:06:25 UTC_11_30_2016: !ruby/object:Mushin::ES::Event {}
|
4
|
+
2016-11-30 08:06:29 UTC_11_30_2016: !ruby/object:Mushin::ES::Event {}
|
5
|
+
2016-11-30 08:06:31 UTC_11_30_2016: !ruby/object:Mushin::ES::Event {}
|
6
|
+
2016-11-30 08:06:32 UTC_11_30_2016: !ruby/object:Mushin::ES::Event {}
|
7
|
+
2016-11-30 08:53:50 UTC_11_30_2016: !ruby/object:Mushin::ES::Event {}
|
8
|
+
2016-11-30 09:01:43 UTC_11_30_2016: !ruby/object:Mushin::ES::Event {}
|
9
|
+
2016-11-30 10:03:04 UTC_11_30_2016: !ruby/object:Mushin::ES::Event {}
|
data/lib/mushin/bot.rb
ADDED
@@ -0,0 +1,236 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'rss'
|
3
|
+
require 'cinch'
|
4
|
+
require 'singleton'
|
5
|
+
|
6
|
+
module Mushin
|
7
|
+
# Mushin speaks via eventsourcing, Mushin::Bot allows Mushin to be heard on IRC, RSS, etc.!
|
8
|
+
module Bot
|
9
|
+
|
10
|
+
# def self.config irc_server: nil, irc_channel: nil
|
11
|
+
# self.irc_server = irc_server
|
12
|
+
# self.irc_channel = irc_channel
|
13
|
+
# end
|
14
|
+
|
15
|
+
# class << self
|
16
|
+
# attr_accessor :irc_server
|
17
|
+
# attr_accessor :irc_channel
|
18
|
+
# end
|
19
|
+
|
20
|
+
#def initialize &block
|
21
|
+
# instance_eval &block
|
22
|
+
#end
|
23
|
+
|
24
|
+
# def irc message: nil, &block
|
25
|
+
# IRC.new(message).instance_eval &block
|
26
|
+
# end
|
27
|
+
|
28
|
+
# C&C and allows communication among a number of microservies over a number of context specific #channels
|
29
|
+
# A Distrubted Rule-based system where each node has its rules-engine and post on a channel and get conditions from the channel, continously adopting to the most recent state of the system.
|
30
|
+
class IRC
|
31
|
+
include Singleton
|
32
|
+
|
33
|
+
attr_accessor :bot, :server, :channels, :nick
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
@bot = Cinch::Bot.new
|
37
|
+
@server = ""
|
38
|
+
@channels = []
|
39
|
+
@nick = "mushin_botapp_name"
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.config &block
|
43
|
+
end
|
44
|
+
|
45
|
+
def log message: nil
|
46
|
+
@bot.configure do |c|
|
47
|
+
c.server = @server #Mushin::Bot.irc_server #"irc.freenode.org"
|
48
|
+
c.channels = @channels #[Mushin::Bot.irc_channel] #["#cinch-bots"]
|
49
|
+
end
|
50
|
+
|
51
|
+
@bot.on :connect do |m|
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
@bot.on :join do |m|
|
56
|
+
m.reply "Hello, #{message}"
|
57
|
+
end
|
58
|
+
|
59
|
+
@bot.on :message, "hello" do |m|
|
60
|
+
m.reply "Hello, #{m.user.nick}"
|
61
|
+
end
|
62
|
+
|
63
|
+
@bot.on :exit do |m|
|
64
|
+
m.reply "goodbye, #{m.user.nick}"
|
65
|
+
end
|
66
|
+
|
67
|
+
@bot.start
|
68
|
+
Thread.new do
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
#TODO from console `mushin publish /path/to/event/stream`
|
75
|
+
class RSS
|
76
|
+
def initialize path: nil, key: nil, url: "/", port: 9999
|
77
|
+
rss url: url, port: port
|
78
|
+
@data = SSD.dump path, key unless path.nil? || key.nil?
|
79
|
+
end
|
80
|
+
def rss url: "/", port: "9494"
|
81
|
+
server = Class.new(Sinatra::Base) do
|
82
|
+
set :port, port
|
83
|
+
get "#{url}" do
|
84
|
+
"yay"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
server.run!
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
#stream = Mushin::EventStream.new
|
95
|
+
#stream.rss url: "/eventstream", port: 9999
|
96
|
+
|
97
|
+
=begin
|
98
|
+
x = "crazy"
|
99
|
+
get "/" do
|
100
|
+
rss = RSS::Maker.make("atom") do |maker|
|
101
|
+
maker.channel.author = "matz"
|
102
|
+
maker.channel.updated = Time.now.to_s
|
103
|
+
maker.channel.about = "http://www.ruby-lang.org/en/feeds/news.rss"
|
104
|
+
maker.channel.title = "upjoystream::v1::bots"
|
105
|
+
maker.channel.description = "upjoystream::v1::bots logsdfssfdasfasfasfasdfasdflasdfsafasfasf"
|
106
|
+
|
107
|
+
maker.items.new_item do |item|
|
108
|
+
item.link = "http://www.ruby-lang.org/en/news/2010/12/25/ruby-1-9-2-p136-is-released/"
|
109
|
+
item.title = "ass"
|
110
|
+
item.updated = Time.now.to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
maker.items.image_item do |item|
|
114
|
+
item.link = "http://www.ruby-lang.org/en/news/2010/12/25/ruby-1-9-2-p136-is-released/"
|
115
|
+
item.title = "shitssssssssss"
|
116
|
+
item.updated = Time.now.to_s
|
117
|
+
p item.methods
|
118
|
+
item.link = "/home/zotherstupidguy/Pictures/10923261.jpg"
|
119
|
+
#item.image_item = "/home/zotherstupidguy/Pictures/10923261.jpg"
|
120
|
+
item.description = "this is a json turned into xml to be viewed here like shit or maybe stayed as json upjoystream::v1::bots logsdfssfdasfasfasfasdfasdflasdfsafasfasf"
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
p rss.methods
|
125
|
+
return rss.to_s
|
126
|
+
end
|
127
|
+
require 'date'
|
128
|
+
require 'logger'
|
129
|
+
require 'rss'
|
130
|
+
require 'open-uri'
|
131
|
+
|
132
|
+
# UNKNOWN: An unknown message that should always be logged.
|
133
|
+
# FATAL: An unhandleable error that results in a program crash.
|
134
|
+
# ERROR: A handleable error condition.
|
135
|
+
# WARN: A warning.
|
136
|
+
# INFO: Generic (useful) information about system operation.
|
137
|
+
# DEBUG: Low-level information for developers.
|
138
|
+
def self.logger(shift_age: 'daily',
|
139
|
+
datetime_format: '%Y-%m-%d %H:%M:%S',
|
140
|
+
log_dir: 'logs'
|
141
|
+
)
|
142
|
+
Dir.mkdir(log_dir) unless File.exists?(log_dir)
|
143
|
+
logger_file = "#{log_dir}/#{DateTime.now.strftime('%m_%d_%Y')}.log"
|
144
|
+
file = File.open(logger_file, File::WRONLY | File::APPEND | File::CREAT)
|
145
|
+
@log = Logger.new("| tee " + file.path, shift_age)
|
146
|
+
@log.datetime_format = datetime_format
|
147
|
+
@log.info "Utter Log Levels: DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN"
|
148
|
+
return @log
|
149
|
+
end
|
150
|
+
|
151
|
+
rss = RSS::Maker.make("atom") do |maker|
|
152
|
+
maker.channel.author = "matz"
|
153
|
+
maker.channel.updated = Time.now.to_s
|
154
|
+
maker.channel.about = "http://www.ruby-lang.org/en/feeds/news.rss"
|
155
|
+
maker.channel.title = "Example Feed"
|
156
|
+
|
157
|
+
maker.items.new_item do |item|
|
158
|
+
item.link = "http://www.ruby-lang.org/en/news/2010/12/25/ruby-1-9-2-p136-is-released/"
|
159
|
+
item.title = "Ruby 1.9.2-p136 is released"
|
160
|
+
item.updated = Time.now.to_s
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
puts rss
|
165
|
+
|
166
|
+
$log = logger
|
167
|
+
class Domain
|
168
|
+
attr :store
|
169
|
+
attr :query
|
170
|
+
attr :log
|
171
|
+
def initialize id
|
172
|
+
p id
|
173
|
+
end
|
174
|
+
def query params={}
|
175
|
+
end
|
176
|
+
def log params={}
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
d = Domain.new 'id' do
|
181
|
+
store = "sss"
|
182
|
+
end
|
183
|
+
p $log
|
184
|
+
$log.info d
|
185
|
+
|
186
|
+
#===========
|
187
|
+
id = "all the kings men"
|
188
|
+
d = Domain.new do
|
189
|
+
end
|
190
|
+
|
191
|
+
class Domain
|
192
|
+
def initialize
|
193
|
+
end
|
194
|
+
|
195
|
+
def command
|
196
|
+
torrent_bots do
|
197
|
+
tpb query: id
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def query 'id'
|
202
|
+
mongodb path: "xx"
|
203
|
+
ssd
|
204
|
+
redis
|
205
|
+
end
|
206
|
+
|
207
|
+
def log
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
Domain.log.publish("url")
|
212
|
+
#===========
|
213
|
+
|
214
|
+
#p d.to_xml
|
215
|
+
# In mushin, event sourcing is to capture all changes to an a domain state as a sequence of events."
|
216
|
+
# Mushin separates business logic(domain logic) into Commands and Queries
|
217
|
+
# state transitions are important part of our problem space and should be modeled within our domain.
|
218
|
+
|
219
|
+
# Event Sourcing persists each domain object as a sequence of events, which are replayed to reconstruct the current state.
|
220
|
+
#
|
221
|
+
#
|
222
|
+
# ideaA
|
223
|
+
result = d.store # returns the a complete hash thing from what was stored via the command domain object process
|
224
|
+
result = d.query tpb: "ss" # returns a selection from the whole thing of the store
|
225
|
+
|
226
|
+
# seperate microservice for read, and seperate microservice for writes and both communicate via the log regardless of the databases they use.
|
227
|
+
#
|
228
|
+
result = d.log #
|
229
|
+
result = d.log tpb: "ss" # returns the latest log state
|
230
|
+
|
231
|
+
# ideaB
|
232
|
+
#result = Domain.query torrent_bots: "ss"
|
233
|
+
#result = Domain.query tpb: "ss"
|
234
|
+
#result = Domain.query context: "torrent_bots"
|
235
|
+
#result = Domain.query construct: "tpb"
|
236
|
+
=end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Mushin
|
2
|
+
module DSLBuilder
|
3
|
+
module CQRS
|
4
|
+
|
5
|
+
class Command
|
6
|
+
|
7
|
+
# attr for a dsl context constructor class
|
8
|
+
attr_accessor :app_dsl_context_klass
|
9
|
+
|
10
|
+
def initialize context_keyword, &block
|
11
|
+
@app_dsl_context_klass = app_dsl_context_access_method_and_klass(context_keyword, Mushin::DSL)
|
12
|
+
instance_eval &block
|
13
|
+
end
|
14
|
+
|
15
|
+
def construct construct_keyword, &block
|
16
|
+
Construct.new construct_keyword, @app_dsl_context_klass, &block
|
17
|
+
end
|
18
|
+
|
19
|
+
def app_dsl_context_access_method_and_klass(context_keyword, parent_klass)
|
20
|
+
$log.info "dynamically building app dsl context access method for: #{context_keyword}, inside: #{parent_klass}".reverse_color
|
21
|
+
|
22
|
+
parent_klass.class_eval do
|
23
|
+
define_method(context_keyword) do |&block|
|
24
|
+
parent_klass.const_get(context_keyword.capitalize).new &block #if block_given?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
k = Class.new do
|
29
|
+
def initialize &block
|
30
|
+
instance_eval &block
|
31
|
+
end
|
32
|
+
end
|
33
|
+
parent_klass.const_set(context_keyword.capitalize, k) unless parent_klass.const_defined?(context_keyword.capitalize)
|
34
|
+
|
35
|
+
return parent_klass.const_get(context_keyword.capitalize)
|
36
|
+
end
|
37
|
+
|
38
|
+
class Construct
|
39
|
+
attr_accessor :context_klass, :construct_klass, :ext_set
|
40
|
+
|
41
|
+
def initialize construct_keyword, context_klass, &block
|
42
|
+
@construct_keyword = construct_keyword
|
43
|
+
@context_klass = context_klass
|
44
|
+
@ext_set = []
|
45
|
+
|
46
|
+
instance_eval &block
|
47
|
+
|
48
|
+
@construct_klass = dsl_construct_access_method_and_klass(@construct_keyword, @ext_set, @context_klass)
|
49
|
+
end
|
50
|
+
|
51
|
+
def use args = {}
|
52
|
+
@ext_set << args
|
53
|
+
end
|
54
|
+
|
55
|
+
def dsl_construct_access_method_and_klass(construct_keyword, ext_set, parent_klass)
|
56
|
+
$log.info "dynamically building app dsl construct access method for: #{construct_keyword}, inside: #{parent_klass}"
|
57
|
+
ext_set.reverse!
|
58
|
+
parent_klass.class_eval do
|
59
|
+
define_method(construct_keyword) do |args = {}|
|
60
|
+
ext_set.each do |ext|
|
61
|
+
ext[:params].each do |key, value|
|
62
|
+
args.each do |env_key, env_value|
|
63
|
+
if env_key.to_sym == value then
|
64
|
+
ext[:params][key] = env_value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end unless ext[:params].nil?
|
68
|
+
|
69
|
+
ext[:opts].each do |key, value|
|
70
|
+
args.each do |env_key, env_value|
|
71
|
+
if env_key.to_sym == value then
|
72
|
+
ext[:opts][key] = env_value
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end unless ext[:opts].nil?
|
76
|
+
$log.info ext
|
77
|
+
end
|
78
|
+
|
79
|
+
parent_klass.const_get(construct_keyword.capitalize).new args, ext_set
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
k = Class.new do
|
84
|
+
attr_accessor :stack
|
85
|
+
def initialize args={}, ext_set
|
86
|
+
p ext_set
|
87
|
+
@stack = Mushin::Stack.new
|
88
|
+
|
89
|
+
ext_set.each do |ext|
|
90
|
+
@stack.insert_before 0, ext[:ext], ext[:opts], ext[:params]
|
91
|
+
#@stack.insert_after_each (Mushin::ES::EventStream)
|
92
|
+
end
|
93
|
+
|
94
|
+
@stack.call
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
parent_klass.const_set(construct_keyword.capitalize, k) unless parent_klass.const_defined?(construct_keyword.capitalize)
|
99
|
+
|
100
|
+
return parent_klass.const_get(construct_keyword.capitalize)
|
101
|
+
end
|
102
|
+
end # end of Construct klass
|
103
|
+
end # end of Command klass (Context klass)
|
104
|
+
end # end of CQRS module
|
105
|
+
end # end of DSLBuilder module
|
106
|
+
end # end of Mushin module
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Mushin
|
2
|
+
module DSLBuilder
|
3
|
+
module CQRS
|
4
|
+
class Query
|
5
|
+
|
6
|
+
def initialize &block
|
7
|
+
@app_dsl_query_klass = app_dsl_query_access_method_and_klass("query", Mushin::DSL)
|
8
|
+
instance_eval &block
|
9
|
+
end
|
10
|
+
|
11
|
+
def construct construct_keyword, &block
|
12
|
+
Construct.new construct_keyword, @app_dsl_query_klass, &block
|
13
|
+
end
|
14
|
+
|
15
|
+
def app_dsl_query_access_method_and_klass(query_keyword, parent_klass)
|
16
|
+
$log.info "Query for: #{query_keyword}, inside: #{parent_klass}"
|
17
|
+
|
18
|
+
parent_klass.class_eval do
|
19
|
+
define_method(query_keyword) do |&block|
|
20
|
+
parent_klass.const_get(query_keyword.capitalize).new &block #if block_given?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
k = Class.new do
|
25
|
+
def initialize &block
|
26
|
+
instance_eval &block
|
27
|
+
end
|
28
|
+
end
|
29
|
+
parent_klass.const_set(query_keyword.capitalize, k) unless parent_klass.const_defined?(query_keyword.capitalize)
|
30
|
+
return parent_klass.const_get(query_keyword.capitalize)
|
31
|
+
end
|
32
|
+
|
33
|
+
class Construct
|
34
|
+
attr_accessor :context_klass, :construct_klass, :ext_set
|
35
|
+
|
36
|
+
def initialize construct_keyword, context_klass, &block
|
37
|
+
|
38
|
+
|
39
|
+
@construct_keyword = construct_keyword
|
40
|
+
@context_klass = context_klass
|
41
|
+
@ext_set = []
|
42
|
+
|
43
|
+
instance_eval &block
|
44
|
+
|
45
|
+
@construct_klass = dsl_construct_access_method_and_klass(@construct_keyword, @ext_set, @context_klass)
|
46
|
+
end
|
47
|
+
|
48
|
+
def use args = {}
|
49
|
+
@ext_set << args
|
50
|
+
end
|
51
|
+
|
52
|
+
def dsl_construct_access_method_and_klass(construct_keyword, ext_set, parent_klass)
|
53
|
+
|
54
|
+
|
55
|
+
$log.info "Query for: #{construct_keyword}, inside: #{parent_klass}"
|
56
|
+
ext_set.reverse!
|
57
|
+
parent_klass.class_eval do
|
58
|
+
define_method(construct_keyword) do |args = {}|
|
59
|
+
|
60
|
+
|
61
|
+
ext_set.each do |ext|
|
62
|
+
ext[:params].each do |key, value|
|
63
|
+
args.each do |env_key, env_value|
|
64
|
+
if env_key.to_sym == value then
|
65
|
+
ext[:params][key] = env_value
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end unless ext[:params].nil?
|
69
|
+
|
70
|
+
ext[:opts].each do |key, value|
|
71
|
+
args.each do |env_key, env_value|
|
72
|
+
if env_key.to_sym == value then
|
73
|
+
ext[:opts][key] = env_value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end unless ext[:opts].nil?
|
77
|
+
$log.info ext
|
78
|
+
end
|
79
|
+
|
80
|
+
obj = parent_klass.const_get(construct_keyword.capitalize).new args, ext_set
|
81
|
+
|
82
|
+
Mushin::DSL.class_eval do
|
83
|
+
define_method(construct_keyword) do |&block|
|
84
|
+
#p "need to get this #{construct_keyword} and create a method of it inside Mushin::DSL, with the value of obj: #{obj.stack.call}"
|
85
|
+
#$log.info "Query for: #{construct_keyword}, inside: #{parent_klass}"
|
86
|
+
#return "get the value from @stack.call, some freakin how!!!"
|
87
|
+
return obj.stack.call
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
k = Class.new do
|
95
|
+
attr_accessor :stack
|
96
|
+
def initialize args={}, ext_set
|
97
|
+
p ext_set
|
98
|
+
@stack = Mushin::Stack.new
|
99
|
+
|
100
|
+
ext_set.each do |ext|
|
101
|
+
@stack.insert_before 0, ext[:ext], ext[:opts], ext[:params]
|
102
|
+
end
|
103
|
+
p "printing the stack value #{@stack.call}"
|
104
|
+
return @stack.call
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
parent_klass.const_set(construct_keyword.capitalize, k) unless parent_klass.const_defined?(construct_keyword.capitalize)
|
109
|
+
|
110
|
+
return parent_klass.const_get(construct_keyword.capitalize)
|
111
|
+
end
|
112
|
+
end # end of Construct klass
|
113
|
+
end # end of Query klass
|
114
|
+
end # end of CQRS module
|
115
|
+
end # end of DSLBuilder module
|
116
|
+
end # end of Mushin module
|
data/lib/mushin/domain.rb
CHANGED
@@ -2,13 +2,17 @@ require_relative 'dsl_builder'
|
|
2
2
|
module Mushin
|
3
3
|
|
4
4
|
class Domain
|
5
|
+
# offers a virtual datastore for query requests on the domain object
|
6
|
+
attr_accessor :store, :event_stream
|
7
|
+
|
5
8
|
def self.inherited(subclass)
|
6
|
-
subclass.send :extend, DSLBuilder
|
9
|
+
subclass.send :extend, DSLBuilder
|
7
10
|
subclass.send :include, DSL
|
8
11
|
end
|
9
12
|
|
10
13
|
def initialize &block
|
11
14
|
$log.info "Domain object #{self} is going to instance_eval"
|
15
|
+
#TODO obj.send("#{prop_name}=", query_value)
|
12
16
|
instance_eval &block
|
13
17
|
end
|
14
18
|
end
|
data/lib/mushin/dsl.rb
CHANGED
data/lib/mushin/dsl_builder.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
require 'mushin'
|
1
|
+
#require 'mushin'
|
2
2
|
require_relative 'dsl'
|
3
|
+
require_relative 'cqrs/command'
|
4
|
+
require_relative 'cqrs/query'
|
3
5
|
|
4
6
|
module Mushin
|
5
7
|
|
@@ -7,114 +9,15 @@ module Mushin
|
|
7
9
|
|
8
10
|
# The DSLBuilder context access method
|
9
11
|
def context context_keyword, &block
|
10
|
-
|
12
|
+
p "printing self from inside DSLBuilder:context #{self}"
|
13
|
+
Mushin::DSLBuilder::CQRS::Command.new context_keyword, &block
|
14
|
+
#Mushin::DSLBuilder::CQRS::Context
|
11
15
|
end
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
def initialize context_keyword, &block
|
19
|
-
@app_dsl_context_klass = app_dsl_context_access_method_and_klass(context_keyword, Mushin::DSL)
|
20
|
-
instance_eval &block
|
21
|
-
end
|
22
|
-
|
23
|
-
def construct construct_keyword, &block
|
24
|
-
Construct.new construct_keyword, @app_dsl_context_klass, &block
|
25
|
-
end
|
26
|
-
|
27
|
-
def app_dsl_context_access_method_and_klass(context_keyword, parent_klass)
|
28
|
-
$log.info "dynamically building app dsl context access method for: #{context_keyword}, inside: #{parent_klass}".reverse_color
|
29
|
-
parent_klass.class_eval do
|
30
|
-
define_method(context_keyword) do |&block|
|
31
|
-
p context_keyword
|
32
|
-
parent_klass.const_get(context_keyword.capitalize).new &block #if block_given?
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
k = Class.new do
|
37
|
-
def initialize &block
|
38
|
-
instance_eval &block
|
39
|
-
p "shit in klass #{self}"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
parent_klass.const_set(context_keyword.capitalize, k) unless parent_klass.const_defined?(context_keyword.capitalize)
|
43
|
-
|
44
|
-
return parent_klass.const_get(context_keyword.capitalize)
|
45
|
-
end
|
46
|
-
|
47
|
-
class Construct
|
48
|
-
attr_accessor :context_klass, :construct_klass, :ext_set
|
49
|
-
|
50
|
-
def initialize construct_keyword, context_klass, &block
|
51
|
-
@construct_keyword = construct_keyword
|
52
|
-
@context_klass = context_klass
|
53
|
-
@ext_set = []
|
54
|
-
instance_eval &block
|
55
|
-
|
56
|
-
|
57
|
-
@construct_klass = dsl_construct_access_method_and_klass(@construct_keyword, @ext_set, @context_klass)
|
58
|
-
#konstructor = @construct_klass.new
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
def use args = {}
|
63
|
-
p "**********************"
|
64
|
-
p args
|
65
|
-
p "************will replace with actual values from konstuctor object args**********"
|
66
|
-
@ext_set << args
|
67
|
-
end
|
68
|
-
|
69
|
-
def dsl_construct_access_method_and_klass(construct_keyword, ext_set, parent_klass)
|
70
|
-
$log.info "dynamically building app dsl construct access method for: #{construct_keyword}, inside: #{parent_klass}"
|
71
|
-
ext_set.reverse!
|
72
|
-
parent_klass.class_eval do
|
73
|
-
define_method(construct_keyword) do |args = {}|
|
74
|
-
p "here replace :symbols with values"
|
75
|
-
p args.class
|
76
|
-
ext_set.each do |ext|
|
77
|
-
ext[:params].each do |key, value|
|
78
|
-
args.each do |env_key, env_value|
|
79
|
-
if env_key.to_sym == value then
|
80
|
-
ext[:params][key] = env_value
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end unless ext[:params].nil?
|
84
|
-
|
85
|
-
ext[:opts].each do |key, value|
|
86
|
-
args.each do |env_key, env_value|
|
87
|
-
if env_key.to_sym == value then
|
88
|
-
ext[:opts][key] = env_value
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end unless ext[:opts].nil?
|
92
|
-
$log.info ext
|
93
|
-
end
|
94
|
-
|
95
|
-
parent_klass.const_get(construct_keyword.capitalize).new args, ext_set
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
k = Class.new do
|
100
|
-
attr_accessor :stack
|
101
|
-
def initialize args={}, ext_set
|
102
|
-
p "construct dynamic klass"
|
103
|
-
@stack = Mushin::Stack.new
|
104
|
-
ext_set.each do |ext|
|
105
|
-
p "inside the stack"
|
106
|
-
p ext
|
107
|
-
@stack.insert_before 0, ext[:ext], ext[:opts], ext[:params]
|
108
|
-
end
|
109
|
-
@stack.call
|
110
|
-
end
|
111
|
-
end
|
112
|
-
parent_klass.const_set(construct_keyword.capitalize, k) unless parent_klass.const_defined?(construct_keyword.capitalize)
|
113
|
-
|
17
|
+
def query &block
|
18
|
+
p "printing self from inside DSLBuilder:query #{self}"
|
19
|
+
Mushin::DSLBuilder::CQRS::Query.new &block
|
20
|
+
end
|
114
21
|
|
115
|
-
return parent_klass.const_get(construct_keyword.capitalize)
|
116
|
-
end
|
117
|
-
end # end of Construct klass
|
118
|
-
end # end of Context klass
|
119
22
|
end # end of DSLBuilder module
|
120
23
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Mushin
|
2
|
+
module ES
|
3
|
+
# A domain event is an object that defines an event (something that happens).
|
4
|
+
# A domain event is an event that domain experts care about.
|
5
|
+
class Event
|
6
|
+
attr_accessor :id
|
7
|
+
attr_accessor :timestamp
|
8
|
+
attr_accessor :version
|
9
|
+
attr_accessor :type
|
10
|
+
attr_accessor :title
|
11
|
+
attr_accessor :data
|
12
|
+
def initialize &block
|
13
|
+
instance_eval &block if block_given?
|
14
|
+
Mushin::ES::EventStream.instance.add self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
module Mushin
|
6
|
+
module ES
|
7
|
+
|
8
|
+
#TODO from the console `mushin eventstream path/to/event/stream` this will populate the application with all the events logged in the specified eventstream, meaning all the databases that the system used will populate it as well. looks like migration mechanism.
|
9
|
+
#TODO event stream(s) maybe used via a rule-engine(sitting on IRC chatrooms as a bot) to determine some general actions. The rule-engine bot takes in events as conditions from a number of microservices and sends should be applied actions to the chat room.
|
10
|
+
class EventStream
|
11
|
+
include Singleton
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
end
|
15
|
+
|
16
|
+
# When an event is added to the strea, it is streamed first then stored to a datastore
|
17
|
+
def add event
|
18
|
+
# Stream to IRC
|
19
|
+
Mushin::Bot::IRC.instance.log message: event
|
20
|
+
|
21
|
+
|
22
|
+
#irc server: "irc.freenode.net", channel: "hackspree", nick: "testingasshole"
|
23
|
+
#rss server: "irc.freenode.net", channel: "hackspree", nick: "testingasshole"
|
24
|
+
# store the event
|
25
|
+
Mushin::ES::Store.write dir: "eventstream", name: DateTime.now.strftime('%m_%d_%Y'), data: event
|
26
|
+
end
|
27
|
+
|
28
|
+
def replay
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/mushin/test_helper.rb
CHANGED
@@ -9,18 +9,25 @@ module Mushin
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def call(env)
|
12
|
+
env ||= Hash.new #if env.nil?
|
12
13
|
$log.info "-----------------------------------------------------------------------"
|
13
14
|
$log.info "Ext: #{self} is called with the following options: #{@opts} & params: #{@params}; and env: #{env}".red
|
14
15
|
$log.info "-----------------------------------------------------------------------"
|
15
16
|
|
16
17
|
# Inbound maniuplation
|
17
|
-
|
18
|
+
|
19
|
+
env[:events] ||= []
|
18
20
|
|
19
21
|
$log.info env[:var] = "#{self} new_value_inbound"
|
22
|
+
|
23
|
+
$log.info env[:events] << "#{self} new_event_inbound"
|
24
|
+
|
20
25
|
@ext.call(env)
|
21
26
|
|
22
27
|
#Outbound maniuplation
|
23
|
-
$log.info
|
28
|
+
$log.info env[:var] = "#{self} new_value_outbound"
|
29
|
+
|
30
|
+
$log.info env[:events] << "#{self} new_event_outbound"
|
24
31
|
end
|
25
32
|
end
|
26
33
|
end
|
data/lib/mushin/version.rb
CHANGED
data/lib/mushin.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
require 'middleware'
|
2
|
-
require 'logger'
|
2
|
+
require 'logger'
|
3
3
|
|
4
4
|
require_relative "mushin/version"
|
5
|
+
#require_relative "mushin/es/event"
|
6
|
+
#require_relative "mushin/es/event_stream"
|
5
7
|
require_relative "mushin/stack"
|
6
8
|
require_relative "mushin/ext"
|
7
9
|
require_relative "mushin/domain"
|
8
10
|
require_relative "mushin/generator"
|
9
11
|
require_relative "mushin/test_helper"
|
10
|
-
|
11
|
-
$log = Logger.new(STDOUT)
|
12
|
+
require_relative "mushin/bot"
|
12
13
|
|
13
14
|
class String
|
14
15
|
def black; "\e[30m#{self}\e[0m" end
|
@@ -35,3 +36,31 @@ class String
|
|
35
36
|
def blink; "\e[5m#{self}\e[25m" end
|
36
37
|
def reverse_color; "\e[7m#{self}\e[27m" end
|
37
38
|
end
|
39
|
+
|
40
|
+
module Mushin
|
41
|
+
private
|
42
|
+
# UNKNOWN: An unknown message that should always be logged.
|
43
|
+
# FATAL: An unhandleable error that results in a program crash.
|
44
|
+
# ERROR: A handleable error condition.
|
45
|
+
# WARN: A warning.
|
46
|
+
# INFO: Generic (useful) information about system operation.
|
47
|
+
# DEBUG: Low-level information for developers.
|
48
|
+
def self.logger(shift_age: 'daily',
|
49
|
+
datetime_format: '%Y-%m-%d %H:%M:%S',
|
50
|
+
log_dir: 'log'
|
51
|
+
)
|
52
|
+
Dir.mkdir(log_dir) unless File.exists?(log_dir)
|
53
|
+
logger_file = "#{log_dir}/#{DateTime.now.strftime('%m_%d_%Y')}.log"
|
54
|
+
file = File.open(logger_file, File::APPEND | File::WRONLY | File::CREAT)
|
55
|
+
file.sync = true
|
56
|
+
#file = File.open(logger_file, File::WRONLY | File::APPEND)
|
57
|
+
@log = Logger.new("| tee " + file.path, shift_age)
|
58
|
+
@log.datetime_format = datetime_format
|
59
|
+
#@log.progname = 'eventstream'
|
60
|
+
|
61
|
+
#@log.info "Mushin Log Levels: DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN"
|
62
|
+
return @log
|
63
|
+
end
|
64
|
+
|
65
|
+
$log = logger #Logger.new(STDOUT)
|
66
|
+
end
|
data/mushin.gemspec
CHANGED
@@ -37,5 +37,12 @@ Gem::Specification.new do |spec|
|
|
37
37
|
spec.add_development_dependency "thor" #, "~> 0.3"
|
38
38
|
spec.add_runtime_dependency "thor" #, "~> 0.3"
|
39
39
|
|
40
|
+
spec.add_runtime_dependency "sinatra" #, "~> 0.3"
|
41
|
+
spec.add_runtime_dependency "ssd" #, "~> 0.3"
|
42
|
+
spec.add_runtime_dependency "cinch" #, "~> 0.3"
|
43
|
+
|
44
|
+
# favouring ore for gem generation over bundler, as it providers a fine-grained customization
|
45
|
+
spec.add_runtime_dependency "ore" #, "~> 0.3"
|
46
|
+
|
40
47
|
#TODO http://guides.rubygems.org/security/
|
41
48
|
end
|
data/samples/sample1.rb
CHANGED
@@ -1,16 +1,35 @@
|
|
1
|
-
require 'mushin'
|
2
|
-
|
1
|
+
#require 'mushin'
|
2
|
+
require_relative './../lib/mushin'
|
3
3
|
#$log.level = Logger::WARN
|
4
4
|
module Sample
|
5
5
|
|
6
6
|
class TBP < Mushin::Test::Sample::Ext; end
|
7
7
|
class SSD < Mushin::Test::Sample::Ext; end
|
8
|
+
class SSDS < Mushin::Test::Sample::Ext
|
9
|
+
def call(env)
|
10
|
+
env ||= Hash.new
|
11
|
+
env[:shit] = "coool"
|
12
|
+
super
|
13
|
+
return env
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class SSDA < Mushin::Test::Sample::Ext
|
18
|
+
def call(env)
|
19
|
+
env ||= Hash.new
|
20
|
+
env[:nana] = "nana_what"
|
21
|
+
super
|
22
|
+
return env
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
8
26
|
|
9
27
|
class RUTracker < Mushin::Test::Sample::Ext; end
|
10
28
|
class Mongodb < Mushin::Test::Sample::Ext; end
|
11
29
|
|
12
30
|
|
13
31
|
class Domain < Mushin::Domain
|
32
|
+
# execution model
|
14
33
|
context 'torrent_bots' do
|
15
34
|
construct 'tpb' do
|
16
35
|
use ext: Sample::TBP, params: {}, opts: {"search_results" => :search_result_max}
|
@@ -19,21 +38,50 @@ module Sample
|
|
19
38
|
use ext: Sample::SSD, params: {}, opts: {"ssd_path"=> :storage_path}
|
20
39
|
end
|
21
40
|
construct 'rutracker' do
|
22
|
-
|
23
|
-
|
41
|
+
use ext: Sample::RUTracker, params: {"search_results" => :search_result_max}
|
42
|
+
use ext: Sample::Mongodb, params: {"search_results" => :search_result_max}
|
24
43
|
end
|
25
44
|
end
|
45
|
+
|
46
|
+
# query model
|
47
|
+
query do
|
48
|
+
construct 'torrents' do
|
49
|
+
use ext: Sample::SSDS, params: {"seeders" => :seeders}, opts: {"ssd_path"=> :keyword}
|
50
|
+
use ext: Sample::SSDA, params: {"seeders" => :seeders}, opts: {"ssd_path"=> :keyword}
|
51
|
+
end
|
52
|
+
|
53
|
+
construct 'torrentsB' do
|
54
|
+
use ext: Sample::SSDS, params: {"seeders" => :seeders}, opts: {"ssd_path"=> :keyword}
|
55
|
+
use ext: Sample::SSDA, params: {"seeders" => :seeders}, opts: {"ssd_path"=> :keyword}
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
26
59
|
end
|
27
60
|
|
28
61
|
class App
|
29
62
|
def initialize
|
30
|
-
|
31
|
-
|
63
|
+
params = {}
|
64
|
+
params[:secret] = "8888"
|
65
|
+
|
66
|
+
domain = Domain.new do
|
32
67
|
torrent_bots do
|
33
68
|
tpb search_result_max: "20", storage_path:"crazypath_here"
|
34
|
-
rutracker search_result_max:
|
69
|
+
rutracker search_result_max: params[:secret]
|
35
70
|
end
|
71
|
+
|
72
|
+
query do
|
73
|
+
torrents keyword: "shit", seeders: "30"
|
74
|
+
torrentsB keyword: "nononononon", seeders: "30"
|
75
|
+
end
|
76
|
+
|
36
77
|
end
|
78
|
+
|
79
|
+
p domain.torrents
|
80
|
+
p domain.torrentsB
|
81
|
+
p "kil"
|
82
|
+
|
83
|
+
#return domain.query :some_key # query somthing specific from the virtual domain datastore
|
84
|
+
return domain.store # returns the whole virtual domain datastore
|
37
85
|
end
|
38
86
|
end
|
39
87
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mushin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- zotherstupidguy
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,6 +108,62 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: sinatra
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: ssd
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: cinch
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: ore
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
111
167
|
description: mushin allows you to generate domain-specific frameworks and domain extenstions.
|
112
168
|
email:
|
113
169
|
- zotherstupidguy@gmail.com
|
@@ -117,6 +173,8 @@ extensions: []
|
|
117
173
|
extra_rdoc_files: []
|
118
174
|
files:
|
119
175
|
- ".gitignore"
|
176
|
+
- ".ssd/eventstream/11_29_2016.ssd"
|
177
|
+
- ".ssd/eventstream/11_30_2016.ssd"
|
120
178
|
- ".travis.yml"
|
121
179
|
- CODE_OF_CONDUCT.md
|
122
180
|
- Gemfile
|
@@ -128,9 +186,14 @@ files:
|
|
128
186
|
- bin/setup
|
129
187
|
- exe/mushin
|
130
188
|
- lib/mushin.rb
|
189
|
+
- lib/mushin/bot.rb
|
190
|
+
- lib/mushin/cqrs/command.rb
|
191
|
+
- lib/mushin/cqrs/query.rb
|
131
192
|
- lib/mushin/domain.rb
|
132
193
|
- lib/mushin/dsl.rb
|
133
194
|
- lib/mushin/dsl_builder.rb
|
195
|
+
- lib/mushin/es/event.rb
|
196
|
+
- lib/mushin/es/event_stream.rb
|
134
197
|
- lib/mushin/ext.rb
|
135
198
|
- lib/mushin/generator.rb
|
136
199
|
- lib/mushin/stack.rb
|