climax 0.0.1
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.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/climax.gemspec +30 -0
- data/lib/climax/control_drb.rb +39 -0
- data/lib/climax/version.rb +3 -0
- data/lib/climax.rb +181 -0
- data/test/bin/hello_world +5 -0
- data/test/lib/hello_world.rb +19 -0
- metadata +138 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/climax.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8; mode: ruby -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "climax/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "climax"
|
7
|
+
s.version = Climax::VERSION
|
8
|
+
s.authors = ["Alfred J. Fazio"]
|
9
|
+
s.email = ["alfred.fazio@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/afazio/climax"
|
11
|
+
s.summary = %q{Ruby command line application framework}
|
12
|
+
s.description = %q{Opinionated framework for Ruby CLI applications that provides logging, cli argument parsing, daemonizing, configuration, testing, and even remote control of long running processes}
|
13
|
+
|
14
|
+
s.rubyforge_project = "climax"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_development_dependency "cucumber"
|
24
|
+
|
25
|
+
s.add_runtime_dependency "pry"
|
26
|
+
s.add_runtime_dependency "slop"
|
27
|
+
s.add_runtime_dependency "rspec"
|
28
|
+
s.add_runtime_dependency "cucumber"
|
29
|
+
s.add_runtime_dependency "pry-remote"
|
30
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'drb/drb'
|
2
|
+
|
3
|
+
module Climax
|
4
|
+
class ControlServer
|
5
|
+
def initialize(app)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def log_level
|
10
|
+
@app.log_level
|
11
|
+
end
|
12
|
+
|
13
|
+
def log_level= (level)
|
14
|
+
@app.send_event(:set_log_level, level)
|
15
|
+
end
|
16
|
+
|
17
|
+
def start_debugger
|
18
|
+
@app.send_event(:start_remote_debugger)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class ControlDRb
|
23
|
+
def initialize(app, port)
|
24
|
+
@port = port
|
25
|
+
server = ControlServer.new(app)
|
26
|
+
DRb.start_service(uri, server)
|
27
|
+
end
|
28
|
+
|
29
|
+
def port
|
30
|
+
@port
|
31
|
+
end
|
32
|
+
|
33
|
+
def uri
|
34
|
+
"druby://localhost:#{port}"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
data/lib/climax.rb
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
require "pry"
|
2
|
+
require "slop"
|
3
|
+
require "logger"
|
4
|
+
require "pry-remote"
|
5
|
+
require "climax/version"
|
6
|
+
require "climax/control_drb"
|
7
|
+
|
8
|
+
module Climax
|
9
|
+
module Application
|
10
|
+
|
11
|
+
def initialize(args=[])
|
12
|
+
@args = args.dup
|
13
|
+
options do
|
14
|
+
on :d, :daemon, "Fork application and run in background"
|
15
|
+
on :control_port=, "Override the port for the control DRb to listen on. Default is 7249", :as => :int, :default => 7249
|
16
|
+
on :log_level=, "Set to debug, info, warn, error, or fatal. Default: info.", :default => "info"
|
17
|
+
on :log_file=, "File to log output to. By default logs to stdout.", :default => nil
|
18
|
+
end
|
19
|
+
post_initialize
|
20
|
+
slop.parse
|
21
|
+
@opts = slop
|
22
|
+
if daemonize?
|
23
|
+
exit 0 if !Process.fork.nil?
|
24
|
+
log.debug "Running in background (#{$$})"
|
25
|
+
end
|
26
|
+
log.debug "Starting Control DRb on port #{control_port}"
|
27
|
+
@control_drb = Climax::ControlDRb.new(self, control_port)
|
28
|
+
run
|
29
|
+
end
|
30
|
+
|
31
|
+
def daemonize?
|
32
|
+
@daemonize = opts[:daemon]
|
33
|
+
end
|
34
|
+
|
35
|
+
def log
|
36
|
+
if @log.nil?
|
37
|
+
@log = Logger.new(log_file || $stdout, "daily")
|
38
|
+
@log.level = log_level
|
39
|
+
if log_file
|
40
|
+
@log.formatter = proc do |severity, datetime, progname, msg|
|
41
|
+
datetime = datetime.strftime("%Y-%m-%d %H:%M:%S")
|
42
|
+
"[#{datetime}] #{$$} #{severity} -- #{msg}\n"
|
43
|
+
end
|
44
|
+
else
|
45
|
+
# Give a more concise format when logging to STDOUT
|
46
|
+
@log.formatter = proc do |severity, datetime, progname, msg|
|
47
|
+
"#{severity}: #{msg}\n"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
@log
|
52
|
+
end
|
53
|
+
|
54
|
+
def control_port
|
55
|
+
@control_port ||= opts[:control_port]
|
56
|
+
end
|
57
|
+
|
58
|
+
def control_port= (port)
|
59
|
+
raise "Cannot set control port to #{port}: ControlDRb is already running!" if @control_drb
|
60
|
+
@control_port = port
|
61
|
+
end
|
62
|
+
|
63
|
+
def log_file
|
64
|
+
@log_file ||= opts[:log_file]
|
65
|
+
end
|
66
|
+
|
67
|
+
def log_file= (path)
|
68
|
+
if !@log.nil?
|
69
|
+
warning = "Changing log path to #{path}!"
|
70
|
+
$stderr.write(warning)
|
71
|
+
log.warn(warning)
|
72
|
+
@log = nil
|
73
|
+
end
|
74
|
+
@log_file = path
|
75
|
+
end
|
76
|
+
|
77
|
+
# Return current log_level
|
78
|
+
def log_level
|
79
|
+
@log_level ||= string_to_log_level opts[:log_level]
|
80
|
+
end
|
81
|
+
|
82
|
+
# Set log level to "debug", "warn", "info", etc. or use Logger::DEBUG, etc.
|
83
|
+
def log_level= (level)
|
84
|
+
log.level = @log_level = string_to_log_level(level)
|
85
|
+
log.warn("Changed log level to #{level}")
|
86
|
+
end
|
87
|
+
|
88
|
+
# Example: "debug" => Logger::DEBUG
|
89
|
+
def string_to_log_level (string)
|
90
|
+
return string if string.is_a? Fixnum
|
91
|
+
Logger.const_get(string.upcase)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Raw command line arguments passed to application
|
95
|
+
def args
|
96
|
+
@args
|
97
|
+
end
|
98
|
+
|
99
|
+
# Return instance of Slop
|
100
|
+
def slop
|
101
|
+
@slop ||= Slop.new
|
102
|
+
end
|
103
|
+
|
104
|
+
# Method for wrapping calls to on() and banner(). Simply for readability.
|
105
|
+
# Example:
|
106
|
+
# options do
|
107
|
+
# on 'v', 'verbose', 'More output'
|
108
|
+
# end
|
109
|
+
def options (&block)
|
110
|
+
yield
|
111
|
+
end
|
112
|
+
|
113
|
+
# Run the application
|
114
|
+
def run
|
115
|
+
pre_main
|
116
|
+
_event_loop
|
117
|
+
post_main
|
118
|
+
end
|
119
|
+
|
120
|
+
# Return current options. nil until ClimaxApplication::new has finished running
|
121
|
+
def opts
|
122
|
+
@opts
|
123
|
+
end
|
124
|
+
|
125
|
+
# Set a command line option ala Slop
|
126
|
+
def on (*args)
|
127
|
+
slop.on(*args)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Set help banner output ala Slop
|
131
|
+
def banner (*args)
|
132
|
+
slop.banner(*args)
|
133
|
+
end
|
134
|
+
|
135
|
+
def command (cmd, &block)
|
136
|
+
slop.command(cmd, block)
|
137
|
+
end
|
138
|
+
|
139
|
+
def _event_loop
|
140
|
+
while true
|
141
|
+
event = _next_event
|
142
|
+
|
143
|
+
unless event.nil?
|
144
|
+
case event.type
|
145
|
+
when :set_log_level then log_level = event.payload
|
146
|
+
when :start_remote_debugger then binding.remote_pry
|
147
|
+
when :quit then exit
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
result = main
|
152
|
+
|
153
|
+
exit result if result.is_a? Fixnum
|
154
|
+
raise result if result.is_a? String
|
155
|
+
raise "Unrecognized return value type: (#{result.class}: #{result}). Only recognize strings, ints, or nil" if !result.nil?
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def send_event (type, payload=nil)
|
160
|
+
events_mutex.synchronize {
|
161
|
+
events.unshift OpenStruct.new(:type => type, :payload => payload)
|
162
|
+
}
|
163
|
+
end
|
164
|
+
|
165
|
+
def events
|
166
|
+
@events ||= []
|
167
|
+
end
|
168
|
+
|
169
|
+
def _next_event
|
170
|
+
events_mutex.synchronize {
|
171
|
+
events.pop
|
172
|
+
}
|
173
|
+
end
|
174
|
+
|
175
|
+
def events_mutex
|
176
|
+
@events_mutex ||= Mutex.new
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
|
2
|
+
require 'climax'
|
3
|
+
|
4
|
+
module HelloWorld
|
5
|
+
class Application
|
6
|
+
include Climax::Application
|
7
|
+
|
8
|
+
def post_initialize
|
9
|
+
options do
|
10
|
+
on 'v', 'verbose', 'More verbose'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def main
|
15
|
+
puts "Hello World!"
|
16
|
+
sleep 3
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: climax
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alfred J. Fazio
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: pry
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: slop
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: cucumber
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: pry-remote
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Opinionated framework for Ruby CLI applications that provides logging,
|
95
|
+
cli argument parsing, daemonizing, configuration, testing, and even remote control
|
96
|
+
of long running processes
|
97
|
+
email:
|
98
|
+
- alfred.fazio@gmail.com
|
99
|
+
executables: []
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files: []
|
102
|
+
files:
|
103
|
+
- .gitignore
|
104
|
+
- Gemfile
|
105
|
+
- Rakefile
|
106
|
+
- climax.gemspec
|
107
|
+
- lib/climax.rb
|
108
|
+
- lib/climax/control_drb.rb
|
109
|
+
- lib/climax/version.rb
|
110
|
+
- test/bin/hello_world
|
111
|
+
- test/lib/hello_world.rb
|
112
|
+
homepage: https://github.com/afazio/climax
|
113
|
+
licenses: []
|
114
|
+
post_install_message:
|
115
|
+
rdoc_options: []
|
116
|
+
require_paths:
|
117
|
+
- lib
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ! '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
none: false
|
126
|
+
requirements:
|
127
|
+
- - ! '>='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
requirements: []
|
131
|
+
rubyforge_project: climax
|
132
|
+
rubygems_version: 1.8.25
|
133
|
+
signing_key:
|
134
|
+
specification_version: 3
|
135
|
+
summary: Ruby command line application framework
|
136
|
+
test_files:
|
137
|
+
- test/bin/hello_world
|
138
|
+
- test/lib/hello_world.rb
|