plow 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,123 @@
1
+ # encoding: UTF-8
2
+
3
+ class Plow
4
+ # `Plow::Dependencies` is a class-methods-only **singleton** class that performs both strict
5
+ # parse-time dependency checking and simple, elegant run-time dependency warning.
6
+ #
7
+ # My preferred mental model is to consider software library dependencies as a snapshot in time.
8
+ # I also make the assumption, sometimes incorrectly, that a newer version of a software library
9
+ # is not always a better version.
10
+ #
11
+ # `Plow::Dependencies` automatically enforces a strict parse-time check for the
12
+ # `REQUIRED_RUBY_VERSION` on both application and development processes for the `Plow` library.
13
+ # (i.e. `bin/plow`, `rake`, `spec`, etc) Because of this, I've ensured this file is
14
+ # syntactically compatible with Ruby 1.8.6 or higher.
15
+ #
16
+ # Currently, `Plow` does **not** enforce strict parse-time version checking on `DEVELOPMENT_GEMS`.
17
+ # In the future, I would like to experiment with using RubyGems and the `Kernel#gem` method to
18
+ # this end. For now, each developer is responsible for ensuring the correct versions of their
19
+ # necessary development gems are located in the `$LOAD_PATH` on their system.
20
+ #
21
+ # When a gem is required, but a `LoadError` is raised, and rescued, `Plow::Dependencies` can be
22
+ # incorporated into the process to warn a developer of missing development features. Even with a
23
+ # few methods -- `.create_warning_for` and `.warn_at_exit` -- users are automatically warned, in
24
+ # this case at the moment of termination, about gems that could not found be in the `$LOAD_PATH`.
25
+ # Using `Plow::Dependencies` is **not** a mandatory inclusion for all gem requirements, merely a
26
+ # guide to help developers quickly see obstacles in their path.
27
+ #
28
+ # @example Simple usage with the Jeweler gem
29
+ # Plow::Dependencies.warn_at_exit
30
+ # begin
31
+ # require 'jeweler'
32
+ # # work with the Jeweler gem
33
+ # rescue LoadError => e
34
+ # Plow::Dependencies.create_warning_for(e)
35
+ # end
36
+ #
37
+ # @see Plow::Dependencies.create_warning_for
38
+ # @see Plow::Dependencies.warn_at_exit
39
+ class Dependencies
40
+ # For now, starting with Ruby 1.9.1 but I would like to experiment with compatibility with Ruby >= 1.9.1 in the future.
41
+ REQUIRED_RUBY_VERSION = '1.9.1'
42
+
43
+ # bluecloth is a hidden yard dependency for markdown support
44
+ DEVELOPMENT_GEMS = {
45
+ :jeweler => '1.3.0',
46
+ :rspec => '1.2.9',
47
+ :yard => '0.4.0',
48
+ :bluecloth => '2.0.5'
49
+ }
50
+
51
+ # Thanx rspec for bucking the pattern :(
52
+ FILE_NAME_TO_GEM_NAME = {
53
+ :spec => :rspec
54
+ }
55
+
56
+ # Empties the warnings cache. This method is called when the class is required.
57
+ def self.destroy_warnings
58
+ @@warnings_cache = []
59
+ end
60
+ destroy_warnings
61
+
62
+ # Creates and caches a warning from a `LoadError` exception. Warnings are only created for
63
+ # known development gem dependencies.
64
+ #
65
+ # @param [LoadError] error A rescued exception
66
+ # @raise [RuntimeError] Raised when the `LoadError` argument is an unknown development gem.
67
+ def self.create_warning_for(error)
68
+ error.message.match(/no such file to load -- (\w*)/) do |match_data|
69
+ file_name = match_data[1].to_sym
70
+ gem_name = if DEVELOPMENT_GEMS.has_key?(file_name)
71
+ file_name
72
+ elsif FILE_NAME_TO_GEM_NAME.has_key?(file_name)
73
+ FILE_NAME_TO_GEM_NAME[file_name]
74
+ else
75
+ raise "Cannot create a dependency warning for unknown development gem -- #{file_name}"
76
+ end
77
+
78
+ @@warnings_cache << "#{gem_name} --version '#{DEVELOPMENT_GEMS[gem_name]}'"
79
+ end
80
+ end
81
+
82
+ # Displays a warning message to the user on the standard output channel if there are warnings
83
+ # to render.
84
+ #
85
+ # @example Sample warning message
86
+ # The following development gem dependencies could not be found. Without them, some available development features are missing:
87
+ # jeweler --version '1.3.0'
88
+ # rspec --version '1.2.9'
89
+ # yard --version '0.4.0'
90
+ # bluecloth --version '2.0.5'
91
+ def self.render_warnings
92
+ unless @@warnings_cache.empty?
93
+ message = []
94
+ message << "The following development gem dependencies could not be found. Without them, some available development features are missing:"
95
+ message += @@warnings_cache
96
+ puts "\n" + message.join("\n")
97
+ end
98
+ end
99
+
100
+ # Attaches a call to `render_warnings` to `Kernel#at_exit`
101
+ def self.warn_at_exit
102
+ at_exit { render_warnings }
103
+ end
104
+
105
+ private
106
+
107
+ # Checks that the version of the current Ruby process matches the `REQUIRED_RUBY_VERSION`.
108
+ # This method is automatically invoked at the first time this class is required, ensuring the
109
+ # correct Ruby version at parse-time.
110
+ #
111
+ # @param [String] ruby_version Useful for automated specifications. Defaults to `RUBY_VERSION`.
112
+ # @raise [SystemExit] Raised, with a message, when the process is using an incorrect version of Ruby.
113
+ def self.check_ruby_version(ruby_version = RUBY_VERSION)
114
+ unless ruby_version == REQUIRED_RUBY_VERSION
115
+ abort <<-ERROR
116
+ This library requires Ruby #{REQUIRED_RUBY_VERSION}, but you're using #{ruby_version}.
117
+ Please visit http://www.ruby-lang.org/ for installation instructions.
118
+ ERROR
119
+ end
120
+ end
121
+ check_ruby_version
122
+ end
123
+ end
data/lib/plow/errors.rb CHANGED
@@ -1,27 +1,35 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  class Plow
4
+ # Should be raised when the current process is owned by a non-root user.
4
5
  class NonRootProcessOwnerError < StandardError
5
6
  end
6
7
 
8
+ # Should be raised when the user-supplied system user name is invalid.
7
9
  class InvalidSystemUserNameError < StandardError
8
10
  end
9
11
 
12
+ # Should be raised when the user-supplied web-site name is invalid.
10
13
  class InvalidWebSiteNameError < StandardError
11
14
  end
12
15
 
16
+ # Should be raised when the user-supplied web-site alias is invalid.
13
17
  class InvalidWebSiteAliasError < StandardError
14
18
  end
15
19
 
20
+ # Should be raised when the user-supplied system user name is reserved.
16
21
  class ReservedSystemUserNameError < StandardError
17
22
  end
18
23
 
24
+ # Should be raised when the user-supplied system user name is not found when it should be.
19
25
  class SystemUserNameNotFoundError < StandardError
20
26
  end
21
27
 
28
+ # Should be raised when an application root path already exists when it should not.
22
29
  class AppRootAlreadyExistsError < StandardError
23
30
  end
24
31
 
32
+ # Should be raised when a configuration file already exsits when it should not.
25
33
  class ConfigFileAlreadyExistsError < StandardError
26
34
  end
27
35
  end
@@ -1,15 +1,49 @@
1
1
  # encoding: UTF-8
2
-
3
2
  require 'erb'
4
-
5
3
  require 'plow/binding_struct'
6
- require 'plow/strategy/ubuntu_hardy/user_home_web_app'
4
+ require 'plow/strategy/ubuntu_hardy'
7
5
 
8
6
  class Plow
7
+ # `Plow::Generator` is a **context** class.
8
+ #
9
+ # At run-time, `Plow::Generator` selects an appropiate strategy class. Each strategy class
10
+ # implements a specific algorithm for web-site template generation. An instance of
11
+ # `Plow::Generator` is intended to be passed to the choosen strategy object, as it provides
12
+ # read-only data accessors for user-supplied input as well as convience methods that communicate
13
+ # messages to the user and execute commands on the system.
14
+ #
15
+ # Currently, there is a single strategy implementation.
16
+ #
17
+ # @see Plow::Strategy::UbuntuHardy
9
18
  class Generator
10
19
  attr_reader :user_name, :site_name, :site_aliases
11
20
  attr_reader :strategy
12
21
 
22
+ # Instantiates a new `Plow::Generator` object with a user name, site name, and optional
23
+ # site aliases.
24
+ #
25
+ # During instantiation, `Plow::Generator` performs basic data validation on the user-supplied
26
+ # input, raising an exception on any failure. On success, parameters are cached to instance
27
+ # variables with read-only, public accessors. Finally, the correct strategy class is selected.
28
+ # This decision is very simple as there is only 1 strategy class at the moment.
29
+ #
30
+ # @example Initialization with two required arguments
31
+ # generator = Plow::Generator.new('steve', 'www.apple.com')
32
+ #
33
+ # @example Initialization with an optional third argument
34
+ # generator = Plow::Generator.new('steve', 'www.apple.com', 'apple.com')
35
+ #
36
+ # @return [Plow::Generator] A new instance of `Plow::Generator`
37
+ #
38
+ # @param [String] user_name Name of a Linux system account user (e.g. steve)
39
+ # @param [String] site_name Name of the web-site (e.g. www.apple.com)
40
+ # @param [splat] *site_aliases (Optional) List of alias names of the web-site (e.g. apple.com)
41
+ #
42
+ # @raise [Plow::InvalidSystemUserNameError] Raised when a `user_name` is blank or includes an space character
43
+ # @raise [Plow::InvalidWebSiteNameError] Raised when a `site_name` is blank or includes an space character
44
+ # @raise [Plow::InvalidWebSiteAliasError] Raised when any `site_alias` is blank or includes an space character
45
+ #
46
+ # @see Plow::Strategy::UbuntuHardy
13
47
  def initialize(user_name, site_name, *site_aliases)
14
48
  if user_name.blank? || user_name.include?(' ')
15
49
  raise(Plow::InvalidSystemUserNameError, user_name)
@@ -29,18 +63,51 @@ class Plow
29
63
  @site_name = site_name
30
64
  @site_aliases = site_aliases
31
65
 
32
- @strategy = Plow::Strategy::UbuntuHardy::UserHomeWebApp.new(self)
66
+ @strategy = Plow::Strategy::UbuntuHardy.new(self)
33
67
  end
34
68
 
69
+ # Executes the pre-choosen strategy.
70
+ #
71
+ # @example Executing a strategy pre-choosen by a `Plow::Generator` instance
72
+ # generator = Plow::Generator.new('steve', 'www.apple.com')
73
+ # generator.run!
74
+ #
75
+ # @raise [Plow::NonRootProcessOwnerError] Raised when the process is owned by a non-root user
35
76
  def run!
36
77
  raise Plow::NonRootProcessOwnerError unless Process.uid == 0
37
- strategy.execute
78
+ strategy.execute!
38
79
  end
39
80
 
81
+ # Renders a message, via the standard output channel, to the user.
82
+ #
83
+ # @example A sample user message
84
+ # generator.say("Hello World!")
85
+ #
86
+ # @example Sample output
87
+ # ==> Hello World!
88
+ #
89
+ # @param [String] message A brief message to the user
40
90
  def say(message)
41
91
  puts "==> #{message}"
42
92
  end
43
93
 
94
+ # Executes a set of commands in the user's shell enviroment. Any text rendered out to any
95
+ # channel during execution is **not** captured and simply displayed to the user. Leading
96
+ # spaces in a command are stripped away and empty lines are ignored.
97
+ #
98
+ # @example Sample usage
99
+ # generator.shell <<-COMMANDS
100
+ #
101
+ # echo "Hello World!"
102
+ #
103
+ # cat /etc/passwd
104
+ # COMMANDS
105
+ #
106
+ # @example Sample shell execution
107
+ # echo "Hello World!"
108
+ # cat /etc/passwd
109
+ #
110
+ # @param [String] commands A set of commands, delimited by line-breaks
44
111
  def shell(commands)
45
112
  commands.each_line do |command|
46
113
  command.strip!
@@ -48,8 +115,23 @@ class Plow
48
115
  end
49
116
  end
50
117
 
118
+ # Evaluates a template file, located on the user's filesystem, with a context
119
+ #
120
+ # @example Evaluating a template file with a context and writing the result to back disk
121
+ # File.open('/path/to/output/file', 'wt') do |file|
122
+ # generator = Plow::Generator.new('steve', 'www.apple.com')
123
+ # context = { :site_name => generator.site_name }
124
+ #
125
+ # config = generator.evaluate_template('/path/to/template/file', context)
126
+ # file.write(config)
127
+ # end
128
+ #
129
+ # @return [String] The evaluated template data
130
+ # @param [String] template_path A Unix path to a template file
131
+ # @param [Hash] context Key/value pairs, where the key is a template file instance variable,
132
+ # and a value is the value to be substituted during evaluation
51
133
  def evaluate_template(template_path, context)
52
- template = File.read(template_path)
134
+ template = File.read(template_path)
53
135
  context_struct = Plow::BindingStruct.new(context)
54
136
  ERB.new(template).result(context_struct.get_binding)
55
137
  end
@@ -0,0 +1,316 @@
1
+ # encoding: UTF-8
2
+
3
+ class Plow
4
+ class Strategy
5
+ # `Plow::Strategy::UbuntuHardy` is a **strategy** class, conditionally instantiated at
6
+ # run-time, that implements a generator algorithm for it's **context** class,
7
+ # `Plow::Generator`.
8
+ #
9
+ # The algorithm implementation is compatible for and tested with Linux Ubuntu 8.04.3 LTS
10
+ # (Hardy Heron) running the Apache 2.2.8 web-server. For a description of the algorithm,
11
+ # please see `Plow::Strategy::UbuntuHardy#execute!`.
12
+ #
13
+ # This class has a few code smells that I expect to iron out in time. However, I'll worry
14
+ # about this when it comes time to share parts of this algorthm across multiple strategy
15
+ # classes.
16
+ #
17
+ # @see Plow::Strategy::UbuntuHardy#execute!
18
+ # @see Plow::Generator
19
+ class UbuntuHardy
20
+ attr_reader :context, :users_file_path, :vhost_file_name, :vhost_file_path, :vhost_template_file_path
21
+ attr_reader :user_home_path, :sites_home_path, :app_root_path, :app_public_path, :app_log_path
22
+
23
+ # Instantiates a new `Plow::Strategy::UbuntuHardy` object from the context of a
24
+ # `Plow::Generator` instance.
25
+ #
26
+ # @example
27
+ # class Plow
28
+ # class Generator
29
+ # def initialize
30
+ # @strategy = Plow::Strategy::UbuntuHardy.new(self)
31
+ # end
32
+ # end
33
+ # end
34
+ #
35
+ # @return [Plow::Strategy::UbuntuHardy] A new instance
36
+ # @param [Plow::Generator] context A reference to the generator context.
37
+ def initialize(context)
38
+ @context = context
39
+ @users_file_path = "/etc/passwd"
40
+ @vhost_file_name = "#{context.site_name}.conf"
41
+ @vhost_file_path = "/etc/apache2/sites-available/#{vhost_file_name}"
42
+
43
+ @vhost_template_file_path = "#{File.dirname(__FILE__)}/ubuntu_hardy/templates/apache2-vhost.conf"
44
+ end
45
+
46
+ # Starts the generator algorithm. The algorithm works as follows:
47
+ #
48
+ # 1. Check for a system user account, create it if one does not exist
49
+ # 2. Check for a system user home directory, create it if one does not exist
50
+ # 3. Check for a sites home directory within the system user home, create it if one does not
51
+ # exist
52
+ # 4. Create an application root directory within the sites home, but raise an exception if
53
+ # one already exists
54
+ # 5. Create an application public directory
55
+ # 6. Create an application log directory
56
+ # 7. Create an virtual host configuration file, but raise an exception if one already exists
57
+ # 8. Install the new virtual host configuration file into the web server
58
+ #
59
+ # In addition to the below exceptions, this method may pass-up a raised exception from within
60
+ # any of the private instance methods.
61
+ #
62
+ # @raise [Plow::AppRootAlreadyExistsError] Raised if the web-app root path directory
63
+ # aleady exists
64
+ # @raise [Plow::ConfigFileAlreadyExistsError] Raised if a apache2 vhost configuration file
65
+ # cannot be found
66
+ def execute!
67
+ if user_exists?
68
+ say "existing #{context.user_name} user"
69
+ else
70
+ say "creating #{context.user_name} user"
71
+ create_user!
72
+ end
73
+
74
+ if user_home_exists?
75
+ say "existing #{user_home_path}"
76
+ else
77
+ say "creating #{user_home_path}"
78
+ create_user_home!
79
+ end
80
+
81
+ if sites_home_exists?
82
+ say "existing #{sites_home_path}"
83
+ else
84
+ say "creating #{sites_home_path}"
85
+ create_sites_home!
86
+ end
87
+
88
+ if app_root_exists?
89
+ raise(Plow::AppRootAlreadyExistsError, app_root_path)
90
+ else
91
+ say "creating #{app_root_path}"
92
+ create_app_root!
93
+ end
94
+
95
+ @app_public_path = "#{app_root_path}/public"
96
+ say "creating #{@app_public_path}"
97
+ create_app_public!
98
+
99
+ @app_log_path = "#{app_root_path}/log"
100
+ say "creating #{app_log_path}"
101
+ create_app_logs!
102
+
103
+ if vhost_config_exists?
104
+ raise(Plow::ConfigFileAlreadyExistsError, vhost_file_path)
105
+ else
106
+ say "creating #{vhost_file_path}"
107
+ create_vhost_config!
108
+ end
109
+
110
+ say "installing #{vhost_file_path}"
111
+ install_vhost_config!
112
+ end
113
+
114
+ ############################################################################################################
115
+
116
+ private
117
+
118
+ # Proxy method to `Plow::Generator#say`.
119
+ # @param [String] message A user output message
120
+ # @see Plow::Generator#say
121
+ def say(message)
122
+ context.say(message)
123
+ end
124
+
125
+ # Proxy method to `Plow::Generator#shell`.
126
+ # @param [String] commands Shell commands with multi-line support.
127
+ # @see Plow::Generator#shell
128
+ def shell(commands)
129
+ context.shell(commands)
130
+ end
131
+
132
+ # Reads the file at `users_file_path` and yields each user iteratively.
133
+ #
134
+ # @yield [Hash] Each user account
135
+ # @example
136
+ # users do |user|
137
+ # user[:name] #=> [String] The name
138
+ # user[:password] #=> [String] The bogus password
139
+ # user[:id] #=> [Number] The uid number
140
+ # user[:group_ip] #=> [Number] The gid number
141
+ # user[:info] #=> [String] General account info
142
+ # user[:home_path] #=> [String] The path to the home directory
143
+ # user[:shell_path] #=> [String] The path to the default shell
144
+ # end
145
+ def users(&block)
146
+ File.readlines(users_file_path).each do |user_line|
147
+ user_line = user_line.chomp.split(':')
148
+ user = {
149
+ :name => user_line[0],
150
+ :password => user_line[1],
151
+ :id => user_line[2].to_i,
152
+ :group_id => user_line[3].to_i,
153
+ :info => user_line[4],
154
+ :home_path => user_line[5],
155
+ :shell_path => user_line[6]
156
+ }
157
+ yield user
158
+ end
159
+ end
160
+
161
+ ############################################################################################################
162
+
163
+ # Determines if the context.user_name already exists or not.
164
+ #
165
+ # @return [Boolean] `true` if found otherwise `false`
166
+ # @raise [Plow::ReservedSystemUserNameError] Raised if the `context.user_name` is a reserved
167
+ # system user name
168
+ def user_exists?
169
+ users do |user|
170
+ if user[:name] == context.user_name
171
+ unless user[:id] >= 1000 && user[:id] != 65534
172
+ raise(Plow::ReservedSystemUserNameError, context.user_name)
173
+ end
174
+ return true
175
+ end
176
+ end
177
+
178
+ return false
179
+ end
180
+
181
+ # Creates a system user account for `context.user_name`.
182
+ def create_user!
183
+ shell "adduser #{context.user_name}"
184
+ end
185
+
186
+ ############################################################################################################
187
+
188
+ # Determines if a home path for the `context.user_name` already exists. As a side-effect,
189
+ # also correctly sets the `@user_home_path` variable.
190
+ #
191
+ # @return [Boolean] `true` if the path already exists, otherwise `false`
192
+ # @raise [Plow::SystemUserNameNotFoundError] Raised if the `context.user_name` is not found
193
+ # though it is expected to exist
194
+ def user_home_exists?
195
+ users do |user|
196
+ if user[:name] == context.user_name
197
+ @user_home_path = user[:home_path]
198
+ return Dir.exists?(user[:home_path])
199
+ end
200
+ end
201
+
202
+ raise(Plow::SystemUserNameNotFoundError, context.user_name)
203
+ end
204
+
205
+ # Creates a user home directory structure at `user_home_path`.
206
+ def create_user_home!
207
+ shell <<-RUN
208
+ mkdir #{user_home_path}
209
+ chown #{context.user_name}:#{context.user_name} #{user_home_path}
210
+ RUN
211
+ end
212
+
213
+ ############################################################################################################
214
+
215
+ # Determines if the `sites_home_path` already exists. As a side-effect, also correctly
216
+ # sets the `@sites_home_path` variable.
217
+ #
218
+ # @return [Boolean] `true` if the path already exists, otherwise `false`
219
+ def sites_home_exists?
220
+ @sites_home_path = "#{user_home_path}/sites"
221
+ Dir.exists?(sites_home_path)
222
+ end
223
+
224
+ # Creates the sites home directory structure at `sites_home_path`.
225
+ def create_sites_home!
226
+ shell <<-RUN
227
+ mkdir #{sites_home_path}
228
+ chown #{context.user_name}:#{context.user_name} #{sites_home_path}
229
+ RUN
230
+ end
231
+
232
+ ############################################################################################################
233
+
234
+ # Determines if the `app_root_path` already exists. As a side-effect, also correctly
235
+ # sets the `@app_root_path` variable.
236
+ #
237
+ # @return [Boolean] `true` if the path exists, otherwise `false`
238
+ def app_root_exists?
239
+ @app_root_path = "#{sites_home_path}/#{context.site_name}"
240
+ Dir.exists?(app_root_path)
241
+ end
242
+
243
+ # Creates the app root directory structure at `app_root_path`.
244
+ def create_app_root!
245
+ shell <<-RUN
246
+ mkdir #{app_root_path}
247
+ chown #{context.user_name}:#{context.user_name} #{app_root_path}
248
+ RUN
249
+ end
250
+
251
+ ############################################################################################################
252
+
253
+ # Creates the app public directory structure at `app_public_path`.
254
+ def create_app_public!
255
+ shell <<-RUN
256
+ mkdir #{app_public_path}
257
+ touch #{app_public_path}/index.html
258
+ chown -R #{context.user_name}:#{context.user_name} #{app_public_path}
259
+ RUN
260
+ end
261
+
262
+ ############################################################################################################
263
+
264
+ # Creates the app log directory structure at `app_log_path`.
265
+ def create_app_logs!
266
+ shell <<-RUN
267
+ mkdir #{app_log_path}
268
+ mkdir #{app_log_path}/apache2
269
+ chmod 750 #{app_log_path}/apache2
270
+
271
+ touch #{app_log_path}/apache2/access.log
272
+ touch #{app_log_path}/apache2/error.log
273
+
274
+ chmod 640 #{app_log_path}/apache2/*.log
275
+ chown -R #{context.user_name}:#{context.user_name} #{app_log_path}
276
+ chown root -R #{app_log_path}/apache2
277
+ RUN
278
+ end
279
+
280
+ ############################################################################################################
281
+
282
+ # Determines if the apache2 vhost config file already exists.
283
+ #
284
+ # @return [Boolean] `true` if the file exists, otherwise `false`
285
+ def vhost_config_exists?
286
+ Dir.exists?(vhost_file_path)
287
+ end
288
+
289
+ # Creates an apache2 vhost config file at `vhost_file_path` by evaluateing a template file.
290
+ def create_vhost_config!
291
+ File.open(vhost_file_path, 'wt') do |file|
292
+ template_context = {
293
+ :site_name => context.site_name,
294
+ :site_aliases => context.site_aliases,
295
+ :app_public_path => app_public_path,
296
+ :app_log_path => app_log_path
297
+ }
298
+
299
+ config = context.evaluate_template(vhost_template_file_path, template_context)
300
+ file.write(config)
301
+ end
302
+ end
303
+
304
+ ############################################################################################################
305
+
306
+ # Installs the apache2 vhost config file by enabling the site and restarting the web server.
307
+ def install_vhost_config!
308
+ shell <<-RUN
309
+ a2ensite #{vhost_file_name} > /dev/null
310
+ apache2ctl graceful
311
+ RUN
312
+ end
313
+
314
+ end
315
+ end
316
+ end
data/lib/plow.rb CHANGED
@@ -1,18 +1,12 @@
1
1
  # encoding: UTF-8
2
-
3
- unless RUBY_VERSION >= '1.9.1'
4
- abort <<-ERROR
5
- Incompatible ruby version error in #{__FILE__} near line #{__LINE__}
6
- This library requires at least ruby v1.9.1 but you're using ruby v#{RUBY_VERSION}
7
- Please see http://www.ruby-lang.org/
8
- ERROR
9
- end
10
-
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__))
3
+ require 'plow/dependencies' # ruby version guard
11
4
  require 'plow/core_ext/object'
12
-
13
5
  require 'plow/errors'
14
6
  require 'plow/application'
15
7
 
8
+ # Library namespace
16
9
  class Plow
17
- VERSION = "0.1.0"
10
+ # Current stable released version
11
+ VERSION = "1.0.0"
18
12
  end
@@ -1,10 +1,10 @@
1
1
  # encoding: UTF-8
2
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'spec_helper'
3
3
 
4
4
  describe Plow::Application do
5
5
 
6
6
  before(:each) do
7
- @expected_version_stamp = "Plow v0.1.0. Copyright (c) 2009 Ryan Sobol. Licensed under the MIT license."
7
+ @expected_version_stamp = "Plow 1.0.0. Copyright (c) 2009 Ryan Sobol. Licensed under the MIT license."
8
8
  end
9
9
 
10
10
  ##################################################################################################
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+ require 'spec_helper'
4
4
 
5
5
  describe Plow::BindingStruct do
6
6