bundler 0.8.1 → 0.9.0.pre1

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.

Potentially problematic release.


This version of bundler might be problematic. Click here for more details.

Files changed (58) hide show
  1. data/README +7 -0
  2. data/bin/bundle +3 -0
  3. data/lib/bundler.rb +72 -37
  4. data/lib/bundler/cli.rb +64 -68
  5. data/lib/bundler/definition.rb +78 -0
  6. data/lib/bundler/dependency.rb +7 -57
  7. data/lib/bundler/dsl.rb +42 -142
  8. data/lib/bundler/environment.rb +94 -54
  9. data/lib/bundler/index.rb +98 -0
  10. data/lib/bundler/installer.rb +137 -0
  11. data/lib/bundler/remote_specification.rb +1 -1
  12. data/lib/bundler/resolver.rb +20 -50
  13. data/lib/bundler/rubygems.rb +22 -0
  14. data/lib/bundler/source.rb +185 -295
  15. data/lib/bundler/specification.rb +22 -0
  16. data/lib/bundler/templates/Gemfile +4 -0
  17. data/lib/bundler/templates/environment.erb +3 -153
  18. data/lib/bundler/ui.rb +51 -0
  19. data/lib/bundler/vendor/thor.rb +241 -0
  20. data/lib/bundler/vendor/thor/actions.rb +274 -0
  21. data/lib/bundler/vendor/thor/actions/create_file.rb +103 -0
  22. data/lib/bundler/vendor/thor/actions/directory.rb +91 -0
  23. data/lib/bundler/vendor/thor/actions/empty_directory.rb +134 -0
  24. data/lib/bundler/vendor/thor/actions/file_manipulation.rb +223 -0
  25. data/lib/bundler/vendor/thor/actions/inject_into_file.rb +101 -0
  26. data/lib/bundler/vendor/thor/base.rb +515 -0
  27. data/lib/bundler/vendor/thor/core_ext/file_binary_read.rb +9 -0
  28. data/lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  29. data/lib/bundler/vendor/thor/core_ext/ordered_hash.rb +100 -0
  30. data/lib/bundler/vendor/thor/error.rb +27 -0
  31. data/lib/bundler/vendor/thor/group.rb +267 -0
  32. data/lib/bundler/vendor/thor/invocation.rb +178 -0
  33. data/lib/bundler/vendor/thor/parser.rb +4 -0
  34. data/lib/bundler/vendor/thor/parser/argument.rb +67 -0
  35. data/lib/bundler/vendor/thor/parser/arguments.rb +145 -0
  36. data/lib/bundler/vendor/thor/parser/option.rb +132 -0
  37. data/lib/bundler/vendor/thor/parser/options.rb +142 -0
  38. data/lib/bundler/vendor/thor/rake_compat.rb +66 -0
  39. data/lib/bundler/vendor/thor/runner.rb +303 -0
  40. data/lib/bundler/vendor/thor/shell.rb +78 -0
  41. data/lib/bundler/vendor/thor/shell/basic.rb +239 -0
  42. data/lib/bundler/vendor/thor/shell/color.rb +108 -0
  43. data/lib/bundler/vendor/thor/task.rb +111 -0
  44. data/lib/bundler/vendor/thor/util.rb +233 -0
  45. data/lib/bundler/vendor/thor/version.rb +3 -0
  46. metadata +48 -26
  47. data/README.markdown +0 -284
  48. data/Rakefile +0 -81
  49. data/lib/bundler/bundle.rb +0 -314
  50. data/lib/bundler/commands/bundle_command.rb +0 -72
  51. data/lib/bundler/commands/exec_command.rb +0 -36
  52. data/lib/bundler/finder.rb +0 -51
  53. data/lib/bundler/gem_bundle.rb +0 -11
  54. data/lib/bundler/gem_ext.rb +0 -34
  55. data/lib/bundler/runtime.rb +0 -2
  56. data/lib/bundler/templates/app_script.erb +0 -3
  57. data/lib/bundler/templates/environment_picker.erb +0 -4
  58. data/lib/rubygems_plugin.rb +0 -6
@@ -0,0 +1,178 @@
1
+ class Thor
2
+ module Invocation
3
+ def self.included(base) #:nodoc:
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ # Prepare for class methods invocations. This method must return a klass to
9
+ # have the invoked class options showed in help messages in generators.
10
+ #
11
+ def prepare_for_invocation(key, name) #:nodoc:
12
+ case name
13
+ when Symbol, String
14
+ Thor::Util.namespace_to_thor_class_and_task(name.to_s, false)
15
+ else
16
+ name
17
+ end
18
+ end
19
+ end
20
+
21
+ # Make initializer aware of invocations and the initializer proc.
22
+ #
23
+ def initialize(args=[], options={}, config={}, &block) #:nodoc:
24
+ @_invocations = config[:invocations] || Hash.new { |h,k| h[k] = [] }
25
+ @_initializer = [ args, options, config ]
26
+ super
27
+ end
28
+
29
+ # Receives a name and invokes it. The name can be a string (either "task" or
30
+ # "namespace:task"), a Thor::Task, a Class or a Thor instance. If the task
31
+ # cannot be guessed by name, it can also be supplied as second argument.
32
+ #
33
+ # You can also supply the arguments, options and configuration values for
34
+ # the task to be invoked, if none is given, the same values used to
35
+ # initialize the invoker are used to initialize the invoked.
36
+ #
37
+ # ==== Examples
38
+ #
39
+ # class A < Thor
40
+ # def foo
41
+ # invoke :bar
42
+ # invoke "b:hello", ["José"]
43
+ # end
44
+ #
45
+ # def bar
46
+ # invoke "b:hello", ["José"]
47
+ # end
48
+ # end
49
+ #
50
+ # class B < Thor
51
+ # def hello(name)
52
+ # puts "hello #{name}"
53
+ # end
54
+ # end
55
+ #
56
+ # You can notice that the method "foo" above invokes two tasks: "bar",
57
+ # which belongs to the same class and "hello" which belongs to the class B.
58
+ #
59
+ # By using an invocation system you ensure that a task is invoked only once.
60
+ # In the example above, invoking "foo" will invoke "b:hello" just once, even
61
+ # if it's invoked later by "bar" method.
62
+ #
63
+ # When class A invokes class B, all arguments used on A initialization are
64
+ # supplied to B. This allows lazy parse of options. Let's suppose you have
65
+ # some rspec tasks:
66
+ #
67
+ # class Rspec < Thor::Group
68
+ # class_option :mock_framework, :type => :string, :default => :rr
69
+ #
70
+ # def invoke_mock_framework
71
+ # invoke "rspec:#{options[:mock_framework]}"
72
+ # end
73
+ # end
74
+ #
75
+ # As you noticed, it invokes the given mock framework, which might have its
76
+ # own options:
77
+ #
78
+ # class Rspec::RR < Thor::Group
79
+ # class_option :style, :type => :string, :default => :mock
80
+ # end
81
+ #
82
+ # Since it's not rspec concern to parse mock framework options, when RR
83
+ # is invoked all options are parsed again, so RR can extract only the options
84
+ # that it's going to use.
85
+ #
86
+ # If you want Rspec::RR to be initialized with its own set of options, you
87
+ # have to do that explicitely:
88
+ #
89
+ # invoke "rspec:rr", [], :style => :foo
90
+ #
91
+ # Besides giving an instance, you can also give a class to invoke:
92
+ #
93
+ # invoke Rspec::RR, [], :style => :foo
94
+ #
95
+ def invoke(name=nil, task=nil, args=nil, opts=nil, config=nil)
96
+ task, args, opts, config = nil, task, args, opts if task.nil? || task.is_a?(Array)
97
+ args, opts, config = nil, args, opts if args.is_a?(Hash)
98
+
99
+ object, task = _prepare_for_invocation(name, task)
100
+ klass, instance = _initialize_klass_with_initializer(object, args, opts, config)
101
+
102
+ method_args = []
103
+ current = @_invocations[klass]
104
+
105
+ iterator = proc do |_, task|
106
+ unless current.include?(task.name)
107
+ current << task.name
108
+ task.run(instance, method_args)
109
+ end
110
+ end
111
+
112
+ if task
113
+ args ||= []
114
+ method_args = args[Range.new(klass.arguments.size, -1)] || []
115
+ iterator.call(nil, task)
116
+ else
117
+ klass.all_tasks.map(&iterator)
118
+ end
119
+ end
120
+
121
+ protected
122
+
123
+ # Configuration values that are shared between invocations.
124
+ #
125
+ def _shared_configuration #:nodoc:
126
+ { :invocations => @_invocations }
127
+ end
128
+
129
+ # Prepare for invocation in the instance level. In this case, we have to
130
+ # take into account that a just a task name from the current class was
131
+ # given or even a Thor::Task object.
132
+ #
133
+ def _prepare_for_invocation(name, sent_task=nil) #:nodoc:
134
+ if name.is_a?(Thor::Task)
135
+ task = name
136
+ elsif task = self.class.all_tasks[name.to_s]
137
+ object = self
138
+ else
139
+ object, task = self.class.prepare_for_invocation(nil, name)
140
+ task ||= sent_task
141
+ end
142
+
143
+ # If the object was not set, use self and use the name as task.
144
+ object, task = self, name unless object
145
+ return object, _validate_task(object, task)
146
+ end
147
+
148
+ # Check if the object given is a Thor class object and get a task object
149
+ # for it.
150
+ #
151
+ def _validate_task(object, task) #:nodoc:
152
+ klass = object.is_a?(Class) ? object : object.class
153
+ raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base
154
+
155
+ task ||= klass.default_task if klass <= Thor
156
+ task = klass.all_tasks[task.to_s] || Thor::Task::Dynamic.new(task) if task && !task.is_a?(Thor::Task)
157
+ task
158
+ end
159
+
160
+ # Initialize klass using values stored in the @_initializer.
161
+ #
162
+ def _initialize_klass_with_initializer(object, args, opts, config) #:nodoc:
163
+ if object.is_a?(Class)
164
+ klass = object
165
+
166
+ stored_args, stored_opts, stored_config = @_initializer
167
+ args ||= stored_args.dup
168
+ opts ||= stored_opts.dup
169
+
170
+ config ||= {}
171
+ config = stored_config.merge(_shared_configuration).merge!(config)
172
+ [ klass, klass.new(args, opts, config) ]
173
+ else
174
+ [ object.class, object ]
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,4 @@
1
+ require 'thor/parser/argument'
2
+ require 'thor/parser/arguments'
3
+ require 'thor/parser/option'
4
+ require 'thor/parser/options'
@@ -0,0 +1,67 @@
1
+ class Thor
2
+ class Argument #:nodoc:
3
+ VALID_TYPES = [ :numeric, :hash, :array, :string ]
4
+
5
+ attr_reader :name, :description, :required, :type, :default, :banner
6
+ alias :human_name :name
7
+
8
+ def initialize(name, description=nil, required=true, type=:string, default=nil, banner=nil)
9
+ class_name = self.class.name.split("::").last
10
+
11
+ raise ArgumentError, "#{class_name} name can't be nil." if name.nil?
12
+ raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type)
13
+
14
+ @name = name.to_s
15
+ @description = description
16
+ @required = required || false
17
+ @type = (type || :string).to_sym
18
+ @default = default
19
+ @banner = banner || default_banner
20
+
21
+ validate! # Trigger specific validations
22
+ end
23
+
24
+ def usage
25
+ required? ? banner : "[#{banner}]"
26
+ end
27
+
28
+ def required?
29
+ required
30
+ end
31
+
32
+ def show_default?
33
+ case default
34
+ when Array, String, Hash
35
+ !default.empty?
36
+ else
37
+ default
38
+ end
39
+ end
40
+
41
+ protected
42
+
43
+ def validate!
44
+ raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil?
45
+ end
46
+
47
+ def valid_type?(type)
48
+ VALID_TYPES.include?(type.to_sym)
49
+ end
50
+
51
+ def default_banner
52
+ case type
53
+ when :boolean
54
+ nil
55
+ when :string, :default
56
+ human_name.upcase
57
+ when :numeric
58
+ "N"
59
+ when :hash
60
+ "key:value"
61
+ when :array
62
+ "one two three"
63
+ end
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,145 @@
1
+ class Thor
2
+ class Arguments #:nodoc:
3
+ NUMERIC = /(\d*\.\d+|\d+)/
4
+
5
+ # Receives an array of args and returns two arrays, one with arguments
6
+ # and one with switches.
7
+ #
8
+ def self.split(args)
9
+ arguments = []
10
+
11
+ args.each do |item|
12
+ break if item =~ /^-/
13
+ arguments << item
14
+ end
15
+
16
+ return arguments, args[Range.new(arguments.size, -1)]
17
+ end
18
+
19
+ def self.parse(base, args)
20
+ new(base).parse(args)
21
+ end
22
+
23
+ # Takes an array of Thor::Argument objects.
24
+ #
25
+ def initialize(arguments=[])
26
+ @assigns, @non_assigned_required = {}, []
27
+ @switches = arguments
28
+
29
+ arguments.each do |argument|
30
+ if argument.default
31
+ @assigns[argument.human_name] = argument.default
32
+ elsif argument.required?
33
+ @non_assigned_required << argument
34
+ end
35
+ end
36
+ end
37
+
38
+ def parse(args)
39
+ @pile = args.dup
40
+
41
+ @switches.each do |argument|
42
+ break unless peek
43
+ @non_assigned_required.delete(argument)
44
+ @assigns[argument.human_name] = send(:"parse_#{argument.type}", argument.human_name)
45
+ end
46
+
47
+ check_requirement!
48
+ @assigns
49
+ end
50
+
51
+ private
52
+
53
+ def peek
54
+ @pile.first
55
+ end
56
+
57
+ def shift
58
+ @pile.shift
59
+ end
60
+
61
+ def unshift(arg)
62
+ unless arg.kind_of?(Array)
63
+ @pile.unshift(arg)
64
+ else
65
+ @pile = arg + @pile
66
+ end
67
+ end
68
+
69
+ def current_is_value?
70
+ peek && peek.to_s !~ /^-/
71
+ end
72
+
73
+ # Runs through the argument array getting strings that contains ":" and
74
+ # mark it as a hash:
75
+ #
76
+ # [ "name:string", "age:integer" ]
77
+ #
78
+ # Becomes:
79
+ #
80
+ # { "name" => "string", "age" => "integer" }
81
+ #
82
+ def parse_hash(name)
83
+ return shift if peek.is_a?(Hash)
84
+ hash = {}
85
+
86
+ while current_is_value? && peek.include?(?:)
87
+ key, value = shift.split(':')
88
+ hash[key] = value
89
+ end
90
+ hash
91
+ end
92
+
93
+ # Runs through the argument array getting all strings until no string is
94
+ # found or a switch is found.
95
+ #
96
+ # ["a", "b", "c"]
97
+ #
98
+ # And returns it as an array:
99
+ #
100
+ # ["a", "b", "c"]
101
+ #
102
+ def parse_array(name)
103
+ return shift if peek.is_a?(Array)
104
+ array = []
105
+
106
+ while current_is_value?
107
+ array << shift
108
+ end
109
+ array
110
+ end
111
+
112
+ # Check if the peel is numeric ofrmat and return a Float or Integer.
113
+ # Otherwise raises an error.
114
+ #
115
+ def parse_numeric(name)
116
+ return shift if peek.is_a?(Numeric)
117
+
118
+ unless peek =~ NUMERIC && $& == peek
119
+ raise MalformattedArgumentError, "expected numeric value for '#{name}'; got #{peek.inspect}"
120
+ end
121
+
122
+ $&.index('.') ? shift.to_f : shift.to_i
123
+ end
124
+
125
+ # Parse string, i.e., just return the current value in the pile.
126
+ #
127
+ def parse_string(name)
128
+ shift
129
+ end
130
+
131
+ # Raises an error if @non_assigned_required array is not empty.
132
+ #
133
+ def check_requirement!
134
+ unless @non_assigned_required.empty?
135
+ names = @non_assigned_required.map do |o|
136
+ o.respond_to?(:switch_name) ? o.switch_name : o.human_name
137
+ end.join("', '")
138
+
139
+ class_name = self.class.name.split('::').last.downcase
140
+ raise RequiredArgumentMissingError, "no value provided for required #{class_name} '#{names}'"
141
+ end
142
+ end
143
+
144
+ end
145
+ end
@@ -0,0 +1,132 @@
1
+ class Thor
2
+ class Option < Argument #:nodoc:
3
+ attr_reader :aliases, :group
4
+
5
+ VALID_TYPES = [:boolean, :numeric, :hash, :array, :string]
6
+
7
+ def initialize(name, description=nil, required=nil, type=nil, default=nil, banner=nil, group=nil, aliases=nil)
8
+ super(name, description, required, type, default, banner)
9
+ @aliases = [*aliases].compact
10
+ @group = group.to_s.capitalize if group
11
+ end
12
+
13
+ # This parse quick options given as method_options. It makes several
14
+ # assumptions, but you can be more specific using the option method.
15
+ #
16
+ # parse :foo => "bar"
17
+ # #=> Option foo with default value bar
18
+ #
19
+ # parse [:foo, :baz] => "bar"
20
+ # #=> Option foo with default value bar and alias :baz
21
+ #
22
+ # parse :foo => :required
23
+ # #=> Required option foo without default value
24
+ #
25
+ # parse :foo => 2
26
+ # #=> Option foo with default value 2 and type numeric
27
+ #
28
+ # parse :foo => :numeric
29
+ # #=> Option foo without default value and type numeric
30
+ #
31
+ # parse :foo => true
32
+ # #=> Option foo with default value true and type boolean
33
+ #
34
+ # The valid types are :boolean, :numeric, :hash, :array and :string. If none
35
+ # is given a default type is assumed. This default type accepts arguments as
36
+ # string (--foo=value) or booleans (just --foo).
37
+ #
38
+ # By default all options are optional, unless :required is given.
39
+ #
40
+ def self.parse(key, value)
41
+ if key.is_a?(Array)
42
+ name, *aliases = key
43
+ else
44
+ name, aliases = key, []
45
+ end
46
+
47
+ name = name.to_s
48
+ default = value
49
+
50
+ type = case value
51
+ when Symbol
52
+ default = nil
53
+
54
+ if VALID_TYPES.include?(value)
55
+ value
56
+ elsif required = (value == :required)
57
+ :string
58
+ elsif value == :optional
59
+ # TODO Remove this warning in the future.
60
+ warn "Optional type is deprecated. Choose :boolean or :string instead. Assumed to be :boolean."
61
+ :boolean
62
+ end
63
+ when TrueClass, FalseClass
64
+ :boolean
65
+ when Numeric
66
+ :numeric
67
+ when Hash, Array, String
68
+ value.class.name.downcase.to_sym
69
+ end
70
+
71
+ self.new(name.to_s, nil, required, type, default, nil, nil, aliases)
72
+ end
73
+
74
+ def switch_name
75
+ @switch_name ||= dasherized? ? name : dasherize(name)
76
+ end
77
+
78
+ def human_name
79
+ @human_name ||= dasherized? ? undasherize(name) : name
80
+ end
81
+
82
+ def usage(padding=0)
83
+ sample = if banner && !banner.to_s.empty?
84
+ "#{switch_name}=#{banner}"
85
+ else
86
+ switch_name
87
+ end
88
+
89
+ sample = "[#{sample}]" unless required?
90
+
91
+ if aliases.empty?
92
+ (" " * padding) << sample
93
+ else
94
+ "#{aliases.join(', ')}, #{sample}"
95
+ end
96
+ end
97
+
98
+ # Allow some type predicates as: boolean?, string? and etc.
99
+ #
100
+ def method_missing(method, *args, &block)
101
+ given = method.to_s.sub(/\?$/, '').to_sym
102
+ if valid_type?(given)
103
+ self.type == given
104
+ else
105
+ super
106
+ end
107
+ end
108
+
109
+ protected
110
+
111
+ def validate!
112
+ raise ArgumentError, "An option cannot be boolean and required." if boolean? && required?
113
+ end
114
+
115
+ def valid_type?(type)
116
+ VALID_TYPES.include?(type.to_sym)
117
+ end
118
+
119
+ def dasherized?
120
+ name.index('-') == 0
121
+ end
122
+
123
+ def undasherize(str)
124
+ str.sub(/^-{1,2}/, '')
125
+ end
126
+
127
+ def dasherize(str)
128
+ (str.length > 1 ? "--" : "-") + str.gsub('_', '-')
129
+ end
130
+
131
+ end
132
+ end