climax 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in climax.gemspec
4
+ gemspec
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
@@ -0,0 +1,3 @@
1
+ module Climax
2
+ VERSION = "0.0.1"
3
+ 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,5 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- ruby-mode -*-
3
+ $:.unshift(File.expand_path("../../lib", __FILE__))
4
+ require "hello_world"
5
+ HelloWorld::Application.new(ARGV).run
@@ -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