laravel 0.5.1 → 0.7.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.
@@ -3,73 +3,126 @@ module Laravel
3
3
  # application. This allows us to read and update settings in
4
4
  # ./application/config/application.php Furthermore, it allows us to read and
5
5
  # update various options, at one go.
6
- class Configuration < App
7
-
8
- # This method creates dynamic read/update methods exposed by this class.
9
- # For this to work, the exposed functions have a definite naming
10
- # convention: {action}_{setting}, where {action} can be either 'read' or
11
- # 'update', and {setting} can be one of the settings found in the
12
- # configuration file.
13
- #
14
- # For example: calling: update_index("home.php") will update the 'index'
15
- # setting to use 'home.php' also, calling: update_key() will update the
16
- # 'key' to a 32-char long string.
17
- #
18
- # The second example above automatically generates a 32-char string by
19
- # calling 'do_update_key' method implicitely, which returns this string.
20
- #
21
- # The 'do_{method}' methods must be defined in this class, which return the
22
- # manipulated input from callee.
23
- #
24
- def method_missing(name, *args)
25
- # capture the input from callee
26
- value = args[0]
27
-
28
- # understand what the callee is requesting..
29
- dissect = name.to_s.split "_"
30
- action = dissect[0]
31
- setting = dissect[1]
32
-
33
- # lets manipulate the input value if a 'do_{method}' exists
34
- new_value = method("do_#{name}").call(value) if Configuration.method_defined?("do_#{name}".to_sym)
35
- # otherwise, use the passed value without any manipulations
36
- new_value = value if new_value.nil? or new_value.strip.empty?
37
-
38
- # handle the {action} part of the method
39
- # performs a read/update on the Configuration setting.
40
- response = case action
41
- when "read" then __read_config(setting)
42
- when "update" then __update_config(setting, new_value)
43
- else raise InvalidArgumentError
44
- end
45
-
46
- # let the user know when we set the value to an empty string
47
- new_value = "__empty_string__" if new_value.nil? or new_value.strip.empty?
48
-
49
- # Let the user know that we have performed an action
50
- if response and action != "read"
51
- say_success "#{action.capitalize}d configuration: #{setting} => #{new_value}"
6
+ class Configuration
7
+ # include Helpers and AppSupport modules that have the helper methods defined
8
+ include Laravel::Helpers
9
+ include Laravel::AppSupport
10
+
11
+ attr_reader :path, :config
12
+
13
+ # Create a new Configuration class, which helps us to configure
14
+ # an existing Laravel application.
15
+ #
16
+ # ==== Parameters
17
+ # +path+ :: Path to an existing Laravel application, which can
18
+ # either be relative or an absolute path. If path is not supplied,
19
+ # we assume current directory.
20
+ #
21
+ # +config+ :: It can be a comma-separated string or an array or a hash
22
+ # of `key:value` pairs. When creating a new app, +config+ is passed as a
23
+ # comma-separated string.
24
+ #
25
+ # Examples:
26
+ # index:"",key,profiler:on,url:http://laravel.com
27
+ # index,key:some_secret_key,ssl:enabled
28
+ #
29
+ def initialize(path = nil, config = nil)
30
+ self.path = path
31
+
32
+ # try to do anything only if this is a Laravel application
33
+ # otherwise, raise an error
34
+ raise LaravelNotFoundError unless has_laravel?
35
+
36
+ # set the desired configuration options
37
+ self.config = config
38
+
39
+ end
40
+
41
+ # Expand the supplied path for the application.
42
+ #
43
+ # ==== Parameters
44
+ # +path+ :: Path to an existing Laravel application, which can
45
+ # either be relative or an absolute path. If path is not supplied,
46
+ # we assume current directory.
47
+ #
48
+ def path=(path = nil)
49
+ path = Dir.pwd if not path or path.strip.empty?
50
+ @path = File.expand_path(path)
51
+ end
52
+
53
+ # Create a configuration hash from the supplied input format
54
+ #
55
+ # ==== Parameters
56
+ # +config+ :: It can be a comma-separated string or an array or a hash
57
+ # of `key:value` pairs. When creating a new app, +config+ is passed as a
58
+ # comma-separated string.
59
+ #
60
+ # Examples:
61
+ # index:"",key,profiler:on,url:http://laravel.com
62
+ # index,key:some_secret_key,ssl:enabled
63
+ #
64
+ def config=(config = {})
65
+ @config = config.is_a?(Hash) ? config : {}
66
+ config = config.split(",") if config.is_a?(String)
67
+ if config.is_a?(Array)
68
+ config.each do |c|
69
+ c = c.split(":", 2)
70
+ @config[c[0]] = c[1]
71
+ end
72
+ end
73
+ end
74
+
75
+ # Update a configuration setting in the configuration file
76
+ #
77
+ # ==== Parameters
78
+ # +config+ :: one of the configuration settings as provided in the
79
+ # configuration file for the application
80
+ #
81
+ # +value+ :: the new value for the supplied +config+ setting. Note that,
82
+ # for configuration settings that take a boolean value, you can pass values
83
+ # like 'true', 'enabled', 'active', 'on', 1 etc. to signify truth.
84
+ #
85
+ def update(config, value)
86
+ return if unsupported? config
87
+ value = process_input(config, value)
88
+ updated = __update_configuration(config, value)
89
+ value = "__empty_string__" if is_blank?(value)
90
+ if updated
91
+ say_success "Updated configuration: #{config} => #{value}"
52
92
  else
53
- say_failed "Could not #{action} configuration: #{setting.capitalize}!"
93
+ say_failed "Could not update configuration: #{config}"
94
+ end
95
+ end
96
+
97
+ # Reads a configuration setting from the configuration file
98
+ #
99
+ # ==== Parameters
100
+ # +config+ :: one of the configuration settings as provided in the
101
+ # configuration file for the application
102
+ #
103
+ def read(config)
104
+ return if unsupported? config
105
+ value = __read_configuration(config)
106
+ value = "__empty_string__" if is_blank?(value)
107
+ if value
108
+ say_success "Configuration: #{config} => #{value}"
109
+ else
110
+ say_failed "Could not read configuration: #{config}"
54
111
  end
55
112
  end
56
113
 
57
114
  # update the configuration settings by looking at the options
58
115
  # that the user has provided when running the 'new' task.
59
116
  #
60
- def update_from_options
117
+ def from_options
61
118
  # don't do anything, unless options were provided
62
- return unless @options
63
-
64
- # update permissions on storage/ directory (this is the default)
65
- update_permissions_on_storage if @options[:perms]
66
- # update Application Index, if provided
67
- update_index @options[:index] unless @options[:index].nil?
68
- # generate a new key, if asked for.
69
- update_key if @options[:key]
119
+ return if not @config or @config.empty?
120
+ @config.each { |key, value| update(key, value) }
70
121
  end
71
122
 
72
- # lets generate the random string required by the 'update_key' method
123
+ # Process input when we are configuring the Application Key.
124
+ # By default, generates a random 32 char string, but if a string is
125
+ # passed as +value+, returns it without further processing.
73
126
  #
74
127
  # ==== Parameters
75
128
  # +value+:: optional string, that if provided will be used as the new key
@@ -77,16 +130,104 @@ module Laravel
77
130
  #
78
131
  # ==== Returns
79
132
  # String:: the new key for the application
80
- def do_update_key(value = nil)
133
+ #
134
+ def process_input_for_key(value = nil)
135
+ return value unless is_blank?(value)
81
136
  make_md5
82
137
  end
83
138
 
139
+ # Process input when we are configuring the Profiler setting.
140
+ # Simply checks if the supplied +value+ corresponds to a 'truthy' value
141
+ # and returns it.
142
+ #
143
+ # ==== Parameters
144
+ # +value+ :: a string that signifies either the truth or false. It can take
145
+ # multiple values like enabled, active, on, etc. to signify truth.
146
+ #
147
+ # ==== Return
148
+ # +boolean+ :: the new value for the Profiler setting
149
+ #
150
+ def process_input_for_profiler(value)
151
+ __convert_action_to_boolean value
152
+ end
153
+
154
+ # Process input when we are configuring the SSL setting.
155
+ # Simply checks if the supplied +value+ corresponds to a 'truthy' value
156
+ # and returns it.
157
+ #
158
+ # ==== Parameters
159
+ # +value+ :: a string that signifies either the truth or false. It can take
160
+ # multiple values like enabled, active, on, etc. to signify truth.
161
+ #
162
+ # ==== Return
163
+ # +boolean+ :: the new value for the SSL setting
164
+ #
165
+ def process_input_for_ssl(value)
166
+ __convert_action_to_boolean value
167
+ end
168
+
84
169
  private
85
170
 
171
+ # Check if the supplied +config+ setting is supported, at the moment?
172
+ # Currently, this class does not support configuration settings that take
173
+ # a PHP array as their value.
174
+ #
175
+ # ==== Parameters
176
+ # +config+ :: the configuration setting to test
177
+ #
178
+ # ==== Return
179
+ # +boolean+ :: true, if the configuration setting is unsupported
180
+ #
181
+ def unsupported?(config)
182
+ unsupported_configs = [ "languages", "aliases" ]
183
+ unsupported = unsupported_configs.include? config
184
+ say_failed "Configuration: #{config} is not supported!" if unsupported
185
+ unsupported
186
+ end
187
+
188
+ # Process the input +value+ for the given +config+ setting.
189
+ # The method checks to see if a method exists by the name:
190
+ # 'process_input_for_{config}' and if so, passes the +value+
191
+ # to that method for processing, and returns the new value.
192
+ #
193
+ # ==== Parameters
194
+ # +config+ :: the configuration setting that needs the update
195
+ #
196
+ # +value+ :: the input value that was supplied when running the task
197
+ #
198
+ # ==== Return
199
+ # +mixed+ :: the new value after processing the given input
200
+ def process_input(config, value)
201
+ name = "process_input_for_#{config}"
202
+ if Configuration.method_defined? name
203
+ value = method(name).call(value)
204
+ end
205
+ value
206
+ end
207
+
208
+ # This method transforms the given input into true or false
209
+ # so that the user can say things like:
210
+ #
211
+ # laravel config update ssl enabled
212
+ # laravel config update profiler active
213
+ #
214
+ # ==== Parameters
215
+ # +value+ :: the input value that was supplied when running the task
216
+ #
217
+ # ==== Return
218
+ # +boolean+ :: the processed input value
219
+ #
220
+ def __convert_action_to_boolean(value = nil)
221
+ on = [ true, "true", "active", "activated",
222
+ "enable", "enabled", "yes", "on", "1", 1 ]
223
+ on.include?(value) ? true : false
224
+ end
225
+
86
226
  # handle the config update routine.
87
- # this method first checks to see if the current app is a Laravel
88
- # based application, and then performs the update for this setting.
89
- # Finally, it checks whether the update was successful and returns it.
227
+ # this method first makes the required update in the configuration file,
228
+ # then it checks whether the update was successful? If not, the method
229
+ # reverts to the old configuration and returns whether we were successful
230
+ # in making the update or not.
90
231
  #
91
232
  # ==== Parameters
92
233
  # +key+:: the configuration setting which will be updated
@@ -95,22 +236,41 @@ module Laravel
95
236
  # ==== Returns
96
237
  # Boolean:: true if the update was successful.
97
238
  #
98
- def __update_config(key, new_value)
99
- # default to current working directory if path is not specified
239
+ def __update_configuration(key, new_value)
100
240
  conf = config_file
101
-
102
- # try to change configuration only if this is a Laravel application
103
- # otherwise, raise an error
104
- raise LaravelNotFoundError unless has_laravel?
241
+ replace = new_value.is_a?(String) ? "'#{new_value}'" : new_value
242
+ check = new_value.is_a?(String) ? Regexp.escape(replace) : replace
105
243
 
106
244
  # make the required substitution in the configuration file
107
245
  text = File.read conf
108
- text = text.gsub(/'#{key}' => '.*'/, "'#{key}' => '#{new_value}'")
109
- File.open(conf, "w") {|file| file.puts text}
246
+ updated_text = text.gsub(/'#{key}' => .*,/, "'#{key}' => #{replace},")
247
+ File.open(conf, "w") {|file| file.puts updated_text}
110
248
 
111
249
  # check to ensure we were able to update configuration
112
- File.readlines(conf).grep(/'#{key}' => '#{new_value}'/).any?
250
+ updated = File.readlines(conf).grep(/'#{key}' => #{check},/).any?
251
+
252
+ # revert if we could not update the configuration
253
+ File.open(conf, "w") {|file| file.puts text} unless updated
254
+
255
+ # response with a success or failure
256
+ updated
113
257
  end
114
258
 
259
+ # handle the config read routine.
260
+ #
261
+ # ==== Parameters
262
+ # +key+ :: the configuration setting which needs to be read
263
+ #
264
+ # ==== Return
265
+ # +mixed+ :: the current value for the supplied configuration setting
266
+ #
267
+ def __read_configuration(key)
268
+ conf = config_file
269
+
270
+ # make the required substitution in the configuration file
271
+ text = File.read conf
272
+ match = text.match(/'#{key}' => (.*),/)
273
+ match ? match[1] : nil
274
+ end
115
275
  end
116
276
  end
@@ -1,55 +1,27 @@
1
1
  module Laravel
2
2
 
3
- class InvalidArgumentError < StandardError
4
- def initialize(message = "Invalid arguments specified!")
3
+ # A general 'Laravel' error.
4
+ class LaravelError < StandardError
5
+ def initialize(message = "A general error occurred while processing..")
5
6
  super(message)
6
7
  end
7
8
  end
8
9
 
10
+ # Error to be raised when Laravel is expected in a directory, but not found
9
11
  class LaravelNotFoundError < StandardError
10
12
  def initialize(message = "Is this a valid Laravel application?")
11
13
  super(message)
12
14
  end
13
15
  end
14
16
 
15
- class InvalidSourceRepositoryError < StandardError
16
- def initialize(message = "Source for downloading Laravel repository is corrupt!")
17
- super(message)
18
- end
19
- end
20
-
21
- class LaravelError < StandardError
22
- def initialize(message = "A general error occurred while processing the command!")
23
- super(message)
24
- end
25
- end
26
-
27
- class RequiredForceMissingError < StandardError
28
- def initialize(message = "You must pass in --force parameter to force an overwrite!")
29
- super(message)
30
- end
31
- end
32
-
33
- class RequiredLibraryMissingError < StandardError
34
- def initialize(message = nil)
35
- message = message ? "#{message} is required! Please, install it." : "One of the required library is missing, e.g. git, curl, etc.!"
36
- super(message)
37
- end
38
- end
39
-
17
+ # Error to be raised when Expectation is not same as Actual result
18
+ # used in Cucumber Tests
40
19
  class ExpectationNotMetError < StandardError
41
20
  def initialize(message = "Test failed because expectation was not met!")
42
21
  super(message)
43
22
  end
44
23
  end
45
24
 
46
- class FileNotFoundError < StandardError
47
- def initialize(message = nil)
48
- message = message ? "File not found: #{message}" : "Could not find the specified file!"
49
- super(message)
50
- end
51
- end
52
-
53
25
  # Show an error the user in Red, and exit the script, since this is an error!
54
26
  def self.handle_error(error, debug = false)
55
27
  shell = Thor::Shell::Color.new
@@ -59,7 +31,7 @@ module Laravel
59
31
  puts "--"
60
32
  puts error.backtrace
61
33
  end
62
- exit
34
+ exit 128
63
35
  end
64
36
 
65
37
  end
@@ -7,9 +7,6 @@ module Laravel
7
7
  # the official Laravel repository URL which is also the default source for us.
8
8
  LaravelRepo = "http://github.com/laravel/laravel"
9
9
 
10
- # the path to the setting.yml file for this gem
11
- GemSettings = File.join(File.dirname(__FILE__), "settings.yml")
12
-
13
10
  # convert a string to MD5 hash - useful to generate quick random strings.
14
11
  #
15
12
  # ==== Parameters
@@ -20,12 +17,17 @@ module Laravel
20
17
  # +string+ :: a 32-character long MD5'ed string
21
18
  #
22
19
  def make_md5(string = nil)
20
+ # create a random string if one is not provided
23
21
  string ||= (0...32).map{ ('a'..'z').to_a[rand(26)] }.join
22
+ # hash it
24
23
  (Digest::MD5.new << string).to_s
25
24
  end
26
25
 
27
26
  # Check whether the given directory is the current directory.
28
27
  #
28
+ # ==== Parameters
29
+ # +dir+ :: the direcotry to check
30
+ #
29
31
  # ==== Return
30
32
  # +boolean+ :: True, if the app directory is the current directory.
31
33
  #
@@ -37,6 +39,9 @@ module Laravel
37
39
 
38
40
  # Check whether the given directory is empty?
39
41
  #
42
+ # ==== Parameters
43
+ # +dir+ :: the directory to check
44
+ #
40
45
  # ==== Return
41
46
  # +boolean+ :: True, if the app directory is an empty one.
42
47
  #
@@ -57,20 +62,28 @@ module Laravel
57
62
  # and that the +source+ is an online file when +path+ is a file.
58
63
  # +source+ :: Source URL/directory from where the content of the resource will be
59
64
  # downloaded. Please, read information about +path+
65
+ # +using+ :: can be either 'curl' or 'git' to download the resource
60
66
  #
61
67
  # ==== Return
62
68
  # +boolean+ :: true, if the resource was downloaded successfully.
63
69
  #
70
+ # ==== Raises
71
+ # +LaravelError+ :: if the required executable/binary is missing
72
+ #
64
73
  def download_resource(path, source, using)
65
- raise RequiredLibraryMissingError, "curl" if using == "curl" and `which curl`.empty? and `which wget`.empty?
66
- raise RequiredLibraryMissingError, "git" if using == "git"
74
+ using = "curl" if using == "shell"
75
+
76
+ # default to `wget` if `curl` is not found
77
+ using = "wget" if `which curl`.empty?
78
+ # raise an error if required library is not found
79
+ message = "#{using} is required! Please, install it!"
80
+ raise LaravelError, message if `which #{using}`.empty?
67
81
 
68
- using = "wget" if using == "curl" and `which curl`.empty? and not `which wget`.empty?
82
+ # download the resource
69
83
  case using
70
- when "git" then system("git clone -q #{source} #{path}")
84
+ when "git" then system("git clone -q #{source} #{path} &>/dev/null")
71
85
  when "curl" then system("curl -s #{source} > #{path}")
72
86
  when "wget" then system("wget #{source} -O #{path}")
73
- else raise RequiredLibraryMissingError
74
87
  end
75
88
  end
76
89
 
@@ -94,24 +107,16 @@ module Laravel
94
107
  true
95
108
  end
96
109
 
97
- # read the yaml configuration from a file
98
- #
99
- def read_yaml(file)
100
- raise FileNotFoundError, file unless File.exists?(file)
101
- data = YAML.load(File.open(file))
102
- # adjust the 'config' hash by making substitutions
103
- data["config"].each do |setting, matrix|
104
- data["config"].delete(setting) if matrix.has_key?("supported") and not matrix["supported"]
105
- data["config"][setting]["default"] = matrix["factory"] if matrix["default"] == "__factory__"
106
- end
107
- data
108
- end
109
-
110
- # write the configuration to a yaml file
110
+ # checks if a given variable is blank
111
+ #
112
+ # ==== Parameters
113
+ # +var+ :: the variable to check
114
+ #
115
+ # ==== Return
116
+ # +boolean+ :: true, if +var+ is +nil+, or if it is an empty +string+
111
117
  #
112
- def write_yaml(data, file)
113
- raise FileNotFoundError, file unless File.exists?(file)
114
- File.open(file, "w") {|f| f.write(data.to_yaml) }
118
+ def is_blank?(var)
119
+ var.nil? or (var.is_a?(String) and var.strip.empty?)
115
120
  end
116
121
 
117
122
  # This method, simply, imitates the 'say' method that the Thor gem provides us.