rr 1.1.1 → 3.0.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.
Files changed (223) hide show
  1. checksums.yaml +5 -5
  2. data/Appraisals +6 -0
  3. data/CHANGES.md +102 -1
  4. data/CREDITS.md +5 -0
  5. data/Gemfile +3 -0
  6. data/README.md +91 -110
  7. data/Rakefile +43 -0
  8. data/doc/02_syntax_comparison.md +1 -0
  9. data/gemfiles/ruby_19_rspec_2.gemfile +14 -0
  10. data/gemfiles/ruby_19_rspec_2.gemfile.lock +49 -0
  11. data/gemfiles/ruby_19_rspec_2_rails_4.gemfile +15 -0
  12. data/gemfiles/ruby_19_rspec_2_rails_4.gemfile.lock +119 -0
  13. data/lib/rr/class_instance_method_defined.rb +1 -1
  14. data/lib/rr/core_ext/array.rb +2 -0
  15. data/lib/rr/core_ext/hash.rb +2 -0
  16. data/lib/rr/deprecations.rb +97 -0
  17. data/lib/rr/double.rb +28 -10
  18. data/lib/rr/double_definitions/double_definition.rb +39 -16
  19. data/lib/rr/double_definitions/double_definition_create.rb +5 -5
  20. data/lib/rr/double_definitions/double_definition_create_blank_slate.rb +10 -4
  21. data/lib/rr/double_definitions/double_injections/any_instance_of.rb +1 -1
  22. data/lib/rr/double_definitions/double_injections/instance.rb +2 -2
  23. data/lib/rr/double_definitions/strategies/strategy.rb +27 -8
  24. data/lib/rr/double_definitions/strategies/verification/mock.rb +8 -2
  25. data/lib/rr/double_matches.rb +4 -3
  26. data/lib/rr/dsl.rb +152 -0
  27. data/lib/rr/expectations/any_argument_expectation.rb +4 -4
  28. data/lib/rr/expectations/argument_equality_expectation.rb +43 -5
  29. data/lib/rr/injections/double_injection.rb +67 -19
  30. data/lib/rr/injections/method_missing_injection.rb +37 -6
  31. data/lib/rr/integrations.rb +13 -12
  32. data/lib/rr/integrations/decorator.rb +4 -1
  33. data/lib/rr/integrations/minitest_4.rb +1 -1
  34. data/lib/rr/integrations/minitest_4_active_support.rb +1 -1
  35. data/lib/rr/integrations/rspec/invocation_matcher.rb +0 -8
  36. data/lib/rr/integrations/rspec_2.rb +28 -3
  37. data/lib/rr/keyword_arguments.rb +15 -0
  38. data/lib/rr/method_dispatches/base_method_dispatch.rb +22 -5
  39. data/lib/rr/method_dispatches/method_dispatch.rb +21 -10
  40. data/lib/rr/method_dispatches/method_missing_dispatch.rb +14 -5
  41. data/lib/rr/recorded_call.rb +35 -0
  42. data/lib/rr/recorded_calls.rb +23 -9
  43. data/lib/rr/space.rb +15 -5
  44. data/lib/rr/spy_verification.rb +13 -5
  45. data/lib/rr/version.rb +1 -2
  46. data/lib/rr/wildcard_matchers.rb +10 -10
  47. data/lib/rr/without_autohook.rb +7 -14
  48. data/rr.gemspec +14 -5
  49. data/spec/custom_formatter_for_rspec.rb +18 -0
  50. data/spec/custom_formatter_for_rspec_2.rb +40 -0
  51. data/spec/defines_spec_suite_tasks.rb +57 -0
  52. data/spec/fixtures/rubygems_patch_for_187.rb +598 -0
  53. data/spec/global_helper.rb +38 -0
  54. data/spec/spec.opts +3 -0
  55. data/spec/spec_suite_configuration.rb +126 -0
  56. data/spec/spec_suite_runner.rb +47 -0
  57. data/spec/suites.yml +10 -0
  58. data/spec/suites/rspec_2/functional/any_instance_of_spec.rb +147 -0
  59. data/spec/suites/rspec_2/functional/dont_allow_spec.rb +17 -0
  60. data/spec/suites/rspec_2/functional/mock_bang_spec.rb +20 -0
  61. data/spec/suites/rspec_2/functional/mock_instance_of_spec.rb +14 -0
  62. data/spec/suites/rspec_2/functional/mock_instance_of_strong_spec.rb +15 -0
  63. data/spec/suites/rspec_2/functional/mock_proxy_instance_of_spec.rb +15 -0
  64. data/spec/suites/rspec_2/functional/mock_proxy_spec.rb +14 -0
  65. data/spec/suites/rspec_2/functional/mock_spec.rb +17 -0
  66. data/spec/suites/rspec_2/functional/mock_strong_spec.rb +14 -0
  67. data/spec/suites/rspec_2/functional/received_spec.rb +16 -0
  68. data/spec/suites/rspec_2/functional/spy_spec.rb +102 -0
  69. data/spec/suites/rspec_2/functional/stub_bang_spec.rb +20 -0
  70. data/spec/suites/rspec_2/functional/stub_instance_of_spec.rb +15 -0
  71. data/spec/suites/rspec_2/functional/stub_instance_of_strong_spec.rb +15 -0
  72. data/spec/suites/rspec_2/functional/stub_proxy_instance_of_spec.rb +16 -0
  73. data/spec/suites/rspec_2/functional/stub_proxy_spec.rb +45 -0
  74. data/spec/suites/rspec_2/functional/stub_spec.rb +71 -0
  75. data/spec/suites/rspec_2/functional/stub_strong_spec.rb +15 -0
  76. data/spec/suites/rspec_2/functional/wildcard_matchers_spec.rb +128 -0
  77. data/spec/suites/rspec_2/helper.rb +28 -0
  78. data/spec/suites/rspec_2/integration/minitest_4_spec.rb +109 -0
  79. data/spec/suites/rspec_2/integration/minitest_spec.rb +109 -0
  80. data/spec/suites/rspec_2/spec_helper.rb +3 -0
  81. data/spec/suites/rspec_2/support/matchers/wildcard_matcher_matchers.rb +32 -0
  82. data/spec/suites/rspec_2/support/mixins/double_definition_creator_helpers.rb +173 -0
  83. data/spec/suites/rspec_2/support/mixins/mock_definition_creator_helpers.rb +45 -0
  84. data/spec/suites/rspec_2/support/mixins/proxy_definition_creator_helpers.rb +33 -0
  85. data/spec/suites/rspec_2/support/mixins/stub_creator_helpers.rb +43 -0
  86. data/spec/suites/rspec_2/support/mixins/stub_definition_creator_helpers.rb +45 -0
  87. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/argument_expectations_with_never_called_qualifier.rb +39 -0
  88. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/argument_expectations_with_times_called_qualifier.rb +50 -0
  89. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/argument_expectations_without_qualifiers.rb +131 -0
  90. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/dont_allow.rb +148 -0
  91. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_instance_of.rb +26 -0
  92. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_instance_of_strong.rb +28 -0
  93. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_proxy.rb +11 -0
  94. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_strong.rb +37 -0
  95. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mocking.rb +107 -0
  96. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_instance_of.rb +32 -0
  97. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_instance_of_strong.rb +39 -0
  98. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_proxy.rb +11 -0
  99. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_strong.rb +37 -0
  100. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stubbing.rb +57 -0
  101. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/array_flatten_bug.rb +35 -0
  102. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/block_form.rb +31 -0
  103. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/comparing_arity.rb +63 -0
  104. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/object_is_proxy.rb +43 -0
  105. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/sequential_invocations.rb +26 -0
  106. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/setting_implementation.rb +51 -0
  107. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/yields.rb +81 -0
  108. data/spec/suites/rspec_2/support/shared_examples/space.rb +13 -0
  109. data/spec/suites/rspec_2/support/shared_examples/times_called_expectation.rb +9 -0
  110. data/spec/suites/rspec_2/unit/core_ext/array_spec.rb +39 -0
  111. data/spec/suites/rspec_2/unit/core_ext/enumerable_spec.rb +53 -0
  112. data/spec/suites/rspec_2/unit/core_ext/hash_spec.rb +55 -0
  113. data/spec/suites/rspec_2/unit/core_ext/range_spec.rb +41 -0
  114. data/spec/suites/rspec_2/unit/core_ext/regexp_spec.rb +41 -0
  115. data/spec/suites/rspec_2/unit/deprecations_spec.rb +27 -0
  116. data/spec/suites/rspec_2/unit/double_definitions/child_double_definition_create_spec.rb +114 -0
  117. data/spec/suites/rspec_2/unit/double_definitions/double_definition_create_blank_slate_spec.rb +93 -0
  118. data/spec/suites/rspec_2/unit/double_definitions/double_definition_create_spec.rb +446 -0
  119. data/spec/suites/rspec_2/unit/dsl/double_creators_spec.rb +133 -0
  120. data/spec/suites/rspec_2/unit/dsl/space_spec.rb +99 -0
  121. data/spec/suites/rspec_2/unit/dsl/wildcard_matchers_spec.rb +67 -0
  122. data/spec/suites/rspec_2/unit/errors/rr_error_spec.rb +67 -0
  123. data/spec/suites/rspec_2/unit/expectations/any_argument_expectation_spec.rb +48 -0
  124. data/spec/suites/rspec_2/unit/expectations/anything_argument_equality_expectation_spec.rb +14 -0
  125. data/spec/suites/rspec_2/unit/expectations/argument_equality_expectation_spec.rb +135 -0
  126. data/spec/suites/rspec_2/unit/expectations/boolean_argument_equality_expectation_spec.rb +30 -0
  127. data/spec/suites/rspec_2/unit/expectations/hash_including_argument_equality_expectation_spec.rb +92 -0
  128. data/spec/suites/rspec_2/unit/expectations/satisfy_argument_equality_expectation_spec.rb +61 -0
  129. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/any_times_matcher_spec.rb +22 -0
  130. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/at_least_matcher_spec.rb +37 -0
  131. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/at_most_matcher_spec.rb +43 -0
  132. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/integer_matcher_spec.rb +58 -0
  133. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/proc_matcher_spec.rb +35 -0
  134. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/range_matcher_spec.rb +39 -0
  135. data/spec/suites/rspec_2/unit/hash_with_object_id_key_spec.rb +88 -0
  136. data/spec/suites/rspec_2/unit/injections/double_injection/double_injection_spec.rb +533 -0
  137. data/spec/suites/rspec_2/unit/injections/double_injection/double_injection_verify_spec.rb +32 -0
  138. data/spec/suites/rspec_2/unit/integrations/rspec/invocation_matcher_spec.rb +297 -0
  139. data/spec/suites/rspec_2/unit/integrations/rspec_spec.rb +70 -0
  140. data/spec/suites/rspec_2/unit/rr_spec.rb +28 -0
  141. data/spec/suites/rspec_2/unit/space_spec.rb +598 -0
  142. data/spec/suites/rspec_2/unit/spy_verification_spec.rb +133 -0
  143. data/spec/suites/rspec_2/unit/times_called_matchers/any_times_matcher_spec.rb +46 -0
  144. data/spec/suites/rspec_2/unit/times_called_matchers/at_least_matcher_spec.rb +54 -0
  145. data/spec/suites/rspec_2/unit/times_called_matchers/at_most_matcher_spec.rb +69 -0
  146. data/spec/suites/rspec_2/unit/times_called_matchers/integer_matcher_spec.rb +69 -0
  147. data/spec/suites/rspec_2/unit/times_called_matchers/proc_matcher_spec.rb +54 -0
  148. data/spec/suites/rspec_2/unit/times_called_matchers/range_matcher_spec.rb +75 -0
  149. data/spec/suites/rspec_2/unit/times_called_matchers/times_called_matcher_spec.rb +117 -0
  150. data/spec/suites/rspec_2/unit/wildcard_matchers/anything_spec.rb +33 -0
  151. data/spec/suites/rspec_2/unit/wildcard_matchers/boolean_spec.rb +45 -0
  152. data/spec/suites/rspec_2/unit/wildcard_matchers/duck_type_spec.rb +64 -0
  153. data/spec/suites/rspec_2/unit/wildcard_matchers/hash_including_spec.rb +64 -0
  154. data/spec/suites/rspec_2/unit/wildcard_matchers/is_a_spec.rb +55 -0
  155. data/spec/suites/rspec_2/unit/wildcard_matchers/numeric_spec.rb +46 -0
  156. data/spec/suites/rspec_2/unit/wildcard_matchers/satisfy_spec.rb +57 -0
  157. data/spec/support/adapter.rb +22 -0
  158. data/spec/support/adapter_tests/base.rb +45 -0
  159. data/spec/support/adapter_tests/minitest.rb +7 -0
  160. data/spec/support/adapter_tests/rspec.rb +70 -0
  161. data/spec/support/adapter_tests/test_unit.rb +47 -0
  162. data/spec/support/command_runner.rb +105 -0
  163. data/spec/support/generator.rb +56 -0
  164. data/spec/support/integration_tests/base.rb +64 -0
  165. data/spec/support/integration_tests/rails.rb +60 -0
  166. data/spec/support/integration_tests/rails_minitest.rb +13 -0
  167. data/spec/support/integration_tests/rails_rspec.rb +13 -0
  168. data/spec/support/integration_tests/rails_test_unit.rb +13 -0
  169. data/spec/support/integration_tests/rails_test_unit_like.rb +13 -0
  170. data/spec/support/integration_tests/ruby.rb +7 -0
  171. data/spec/support/integration_tests/ruby_minitest.rb +13 -0
  172. data/spec/support/integration_tests/ruby_rspec.rb +13 -0
  173. data/spec/support/integration_tests/ruby_test_unit.rb +13 -0
  174. data/spec/support/matchers/be_a_subset_of_matcher.rb +24 -0
  175. data/spec/support/project/cucumber.rb +50 -0
  176. data/spec/support/project/generator.rb +348 -0
  177. data/spec/support/project/minitest.rb +39 -0
  178. data/spec/support/project/rails.rb +199 -0
  179. data/spec/support/project/rails_minitest.rb +17 -0
  180. data/spec/support/project/rails_rspec.rb +50 -0
  181. data/spec/support/project/rails_test_unit.rb +17 -0
  182. data/spec/support/project/rails_test_unit_like.rb +17 -0
  183. data/spec/support/project/rspec.rb +69 -0
  184. data/spec/support/project/ruby.rb +34 -0
  185. data/spec/support/project/ruby_minitest.rb +11 -0
  186. data/spec/support/project/ruby_rspec.rb +29 -0
  187. data/spec/support/project/ruby_test_unit.rb +11 -0
  188. data/spec/support/project/ruby_test_unit_like.rb +21 -0
  189. data/spec/support/project/test_unit.rb +29 -0
  190. data/spec/support/project/test_unit_like.rb +7 -0
  191. data/spec/support/project/tests_runner.rb +22 -0
  192. data/spec/support/test.sqlite3 +0 -0
  193. data/spec/support/test_case/generator.rb +53 -0
  194. data/spec/support/test_case/minitest.rb +13 -0
  195. data/spec/support/test_case/rspec.rb +19 -0
  196. data/spec/support/test_case/test_unit.rb +21 -0
  197. data/spec/support/test_file/generator.rb +120 -0
  198. data/spec/support/test_file/minitest.rb +19 -0
  199. data/spec/support/test_file/rails_minitest.rb +7 -0
  200. data/spec/support/test_file/rails_rspec.rb +12 -0
  201. data/spec/support/test_file/rails_test_unit.rb +25 -0
  202. data/spec/support/test_file/rspec.rb +33 -0
  203. data/spec/support/test_file/test_unit.rb +36 -0
  204. data/spec/support/test_helper/generator.rb +27 -0
  205. data/spec/support/test_helper/minitest.rb +7 -0
  206. data/spec/support/test_helper/rails.rb +31 -0
  207. data/spec/support/test_helper/rails_minitest.rb +7 -0
  208. data/spec/support/test_helper/rails_rspec.rb +25 -0
  209. data/spec/support/test_helper/rails_test_unit.rb +23 -0
  210. data/spec/support/test_helper/rspec.rb +7 -0
  211. data/spec/support/test_helper/ruby.rb +31 -0
  212. data/spec/support/test_helper/test_unit.rb +7 -0
  213. metadata +240 -19
  214. data/VERSION +0 -1
  215. data/lib/rr/adapters.rb +0 -44
  216. data/lib/rr/adapters/rr_methods.rb +0 -142
  217. data/lib/rr/integrations/rspec_1.rb +0 -46
  218. data/lib/rr/integrations/test_unit_1.rb +0 -63
  219. data/lib/rr/integrations/test_unit_2.rb +0 -15
  220. data/lib/rr/integrations/test_unit_200.rb +0 -27
  221. data/lib/rr/integrations/test_unit_200_active_support.rb +0 -25
  222. data/lib/rr/integrations/test_unit_2_active_support.rb +0 -38
  223. data/lib/rr/proc_from_block.rb +0 -11
data/lib/rr/space.rb CHANGED
@@ -13,9 +13,15 @@ module RR
13
13
  end
14
14
  attr_writer :instance
15
15
 
16
- protected
17
- def method_missing(method_name, *args, &block)
18
- instance.__send__(method_name, *args, &block)
16
+ protected
17
+ if KeywordArguments.fully_supported?
18
+ def method_missing(method_name, *args, **kwargs, &block)
19
+ instance.__send__(method_name, *args, **kwargs, &block)
20
+ end
21
+ else
22
+ def method_missing(method_name, *args, &block)
23
+ instance.__send__(method_name, *args, &block)
24
+ end
19
25
  end
20
26
  end
21
27
 
@@ -79,8 +85,12 @@ module RR
79
85
  Injections::DoubleInjection.reset_double(class << subject; self; end, method_name)
80
86
  end
81
87
 
82
- def record_call(subject, method_name, arguments, block)
83
- @recorded_calls << [subject, method_name, arguments, block]
88
+ def record_call(subject, method_name, arguments, keyword_arguments, block)
89
+ @recorded_calls.add(subject,
90
+ method_name,
91
+ arguments,
92
+ keyword_arguments,
93
+ block)
84
94
  end
85
95
 
86
96
  def blank_slate_whitelist
@@ -13,12 +13,12 @@ module RR
13
13
 
14
14
  include RR::DoubleDefinitions::DoubleDefinition::TimesDefinitionConstructionMethods
15
15
  include RR::DoubleDefinitions::DoubleDefinition::ArgumentDefinitionConstructionMethods
16
-
16
+
17
17
  def ordered
18
18
  @ordered = true
19
19
  self
20
20
  end
21
-
21
+
22
22
  def ordered?
23
23
  @ordered
24
24
  end
@@ -32,7 +32,15 @@ module RR
32
32
  call
33
33
  end
34
34
  end
35
-
35
+
36
+ def subject_inspect
37
+ if subject.respond_to?(:__rr__original_inspect, true)
38
+ subject.__rr__original_inspect
39
+ else
40
+ subject.inspect
41
+ end
42
+ end
43
+
36
44
  protected
37
45
  attr_writer :times_matcher
38
46
 
@@ -40,9 +48,9 @@ module RR
40
48
  # with_no_args and with actually set @argument_expectation
41
49
  args.empty? ? with_no_args : with(*args)
42
50
  end
43
-
51
+
44
52
  def install_method_callback(return_value_block)
45
53
  # Do nothing. This is to support DefinitionConstructionMethods
46
54
  end
47
55
  end
48
- end
56
+ end
data/lib/rr/version.rb CHANGED
@@ -1,5 +1,4 @@
1
-
2
1
  module RR
3
- VERSION = File.read(File.expand_path('../../../VERSION', __FILE__)).strip
2
+ VERSION = '3.0.0'.freeze
4
3
  def self.version; VERSION; end
5
4
  end
@@ -12,7 +12,7 @@ divisible by a certain integer. In use, it might look like this:
12
12
 
13
13
  mock(BananaGrabber).bunch_bananas(divisible_by(5))
14
14
 
15
- To implement this, we need a class RR::WildcardMatchers::DivisibleBy with
15
+ To implement this, we need a class RR::WildcardMatchers::DivisibleBy with
16
16
  these instance methods:
17
17
 
18
18
  * ==(other)
@@ -38,7 +38,7 @@ might look like this:
38
38
  DivisibleBy#==(other) should return true if other is a wildcard matcher that
39
39
  matches the same things as self, so a natural way to write DivisibleBy#== is:
40
40
 
41
-
41
+
42
42
  class RR::WildcardMatchers::DivisibleBy
43
43
  def ==(other)
44
44
  # Ensure that other is actually a DivisibleBy
@@ -86,7 +86,7 @@ false otherwise. In the case of DivisibleBy, wildcard_matches? reads:
86
86
  # If other isn't a number, how can it be divisible by anything?
87
87
  return false unless other.is_a?(Numeric)
88
88
 
89
- # If other is in fact divisible by expected_divisor, then
89
+ # If other is in fact divisible by expected_divisor, then
90
90
  # other modulo expected_divisor should be 0.
91
91
 
92
92
  other % expected_divisor == 0
@@ -105,10 +105,10 @@ But that's less expressive than the original:
105
105
  mock(BananaGrabber).bunch_bananas(divisible_by(5))
106
106
 
107
107
  To be able to use the convenient divisible_by matcher rather than the uglier
108
- DivisibleBy.new version, re-open the module RR::Adapters::RRMethods and
109
- define divisible_by there as a simple wrapper around DivisibleBy.new:
108
+ DivisibleBy.new version, re-open the module RR::DSL and define divisible_by
109
+ there as a simple wrapper around DivisibleBy.new:
110
110
 
111
- module RR::Adapters::RRMethods
111
+ module RR::DSL
112
112
  def divisible_by(expected_divisor)
113
113
  RR::WildcardMatchers::DivisibleBy.new(expected_divisor)
114
114
  end
@@ -134,19 +134,19 @@ Here's all the code for DivisibleBy in one place for easy reference:
134
134
  def inspect
135
135
  "integer divisible by #{expected.divisor}"
136
136
  end
137
-
137
+
138
138
  def wildcard_matches?(other)
139
139
  # If other isn't a number, how can it be divisible by anything?
140
140
  return false unless other.is_a?(Numeric)
141
141
 
142
- # If other is in fact divisible by expected_divisor, then
142
+ # If other is in fact divisible by expected_divisor, then
143
143
  # other modulo expected_divisor should be 0.
144
144
 
145
145
  other % expected_divisor == 0
146
146
  end
147
147
  end
148
-
149
- module RR::Adapters::RRMethods
148
+
149
+ module RR::DSL
150
150
  def divisible_by(expected_divisor)
151
151
  RR::WildcardMatchers::DivisibleBy.new(expected_divisor)
152
152
  end
@@ -6,6 +6,8 @@ require 'rr/core_ext/array'
6
6
  require 'rr/core_ext/range'
7
7
  require 'rr/core_ext/regexp'
8
8
 
9
+ require 'rr/keyword_arguments'
10
+
9
11
  require 'rr/class_instance_method_defined'
10
12
  require 'rr/blank_slate'
11
13
 
@@ -36,7 +38,7 @@ require 'rr/double_definitions/strategies/implementation/proxy'
36
38
  require 'rr/double_definitions/strategies/double_injection/double_injection_strategy'
37
39
  require 'rr/double_definitions/strategies/double_injection/instance'
38
40
  require 'rr/double_definitions/strategies/double_injection/any_instance_of'
39
- require 'rr/adapters/rr_methods'
41
+ require 'rr/dsl'
40
42
  require 'rr/double_definitions/double_injections/instance'
41
43
  require 'rr/double_definitions/double_injections/any_instance_of'
42
44
  require 'rr/double_definitions/double_definition'
@@ -49,8 +51,8 @@ require 'rr/method_dispatches/base_method_dispatch'
49
51
  require 'rr/method_dispatches/method_dispatch'
50
52
  require 'rr/method_dispatches/method_missing_dispatch'
51
53
  require 'rr/hash_with_object_id_key'
54
+ require 'rr/recorded_call'
52
55
  require 'rr/recorded_calls'
53
- require 'rr/proc_from_block'
54
56
 
55
57
  require 'rr/double_definitions/double_definition_create_blank_slate'
56
58
  require 'rr/double_definitions/double_definition_create'
@@ -85,27 +87,22 @@ require 'rr/times_called_matchers/at_most_matcher'
85
87
  require 'rr/spy_verification_proxy'
86
88
  require 'rr/spy_verification'
87
89
 
88
- require 'rr/adapters'
89
90
  require 'rr/integrations'
90
91
  require 'rr/integrations/decorator'
91
92
  require 'rr/integrations/rspec/invocation_matcher'
92
- require 'rr/integrations/rspec_1'
93
93
  require 'rr/integrations/rspec_2'
94
94
  require 'rr/integrations/minitest_4'
95
95
  require 'rr/integrations/minitest_4_active_support'
96
96
  require 'rr/integrations/minitest'
97
97
  require 'rr/integrations/minitest_active_support'
98
- require 'rr/integrations/test_unit_1'
99
- require 'rr/integrations/test_unit_200'
100
- require 'rr/integrations/test_unit_200_active_support'
101
- require 'rr/integrations/test_unit_2'
102
- require 'rr/integrations/test_unit_2_active_support'
98
+
99
+ require 'rr/deprecations'
103
100
 
104
101
  require 'rr/version'
105
102
 
106
103
  module RR
107
104
  class << self
108
- include Adapters::RRMethods
105
+ include DSL
109
106
 
110
107
  (RR::Space.instance_methods - Object.instance_methods).each do |method_name|
111
108
  class_eval((<<-METHOD), __FILE__, __LINE__ + 1)
@@ -117,10 +114,6 @@ module RR
117
114
 
118
115
  attr_accessor :debug
119
116
  alias_method :debug?, :debug
120
-
121
- def ruby_18?
122
- RUBY_VERSION =~ /^1\.8/
123
- end
124
117
  end
125
118
  end
126
119
 
data/rr.gemspec CHANGED
@@ -6,23 +6,32 @@ require File.expand_path('../lib/rr/version', __FILE__)
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = 'rr'
8
8
  gem.version = RR.version
9
- gem.authors = ['Brian Takita', 'Elliot Winkler']
10
- gem.email = ['elliot.winkler@gmail.com']
9
+ gem.authors = ['Kouhei Sutou', 'Brian Takita', 'Elliot Winkler']
10
+ gem.email = ['kou@cozmixng.org']
11
11
  gem.description = 'RR is a test double framework that features a rich selection of double techniques and a terse syntax.'
12
12
  gem.summary = 'RR is a test double framework that features a rich selection of double techniques and a terse syntax.'
13
- gem.homepage = 'http://rr.github.com/rr'
13
+ gem.homepage = 'https://rr.github.io/rr'
14
14
  gem.license = 'MIT'
15
15
 
16
16
  gem.files = FileList[
17
+ 'Appraisals',
17
18
  'CHANGES.md',
18
19
  'CREDITS.md',
20
+ 'Gemfile',
19
21
  'LICENSE',
20
22
  'README.md',
21
- 'VERSION',
23
+ 'Rakefile',
22
24
  'doc/*.md',
25
+ 'gemfiles/**/*',
23
26
  'lib/**/*.rb',
24
- 'rr.gemspec'
27
+ 'rr.gemspec',
28
+ 'spec/**/*'
25
29
  ].to_a
26
30
 
27
31
  gem.require_paths = ['lib']
32
+
33
+ gem.add_development_dependency("bundler")
34
+ gem.add_development_dependency("rake")
35
+ gem.add_development_dependency("test-unit")
36
+ gem.add_development_dependency("test-unit-rr")
28
37
  end
@@ -0,0 +1,18 @@
1
+ require 'spec/runner/formatter/specdoc_formatter'
2
+
3
+ class CustomFormatterForRSpec < Spec::Runner::Formatter::SpecdocFormatter
4
+ def example_passed(example)
5
+ super
6
+ output.flush
7
+ end
8
+
9
+ def example_pending(example, message)
10
+ super
11
+ output.flush
12
+ end
13
+
14
+ def example_failed(example, counter, failure)
15
+ super
16
+ output.flush
17
+ end
18
+ end
@@ -0,0 +1,40 @@
1
+ require 'rspec/core/formatters/base_text_formatter'
2
+
3
+ class CustomFormatterForRSpec2 < RSpec::Core::Formatters::BaseTextFormatter
4
+ def example_passed(example)
5
+ super(example)
6
+ output.puts passed_output(example)
7
+ output.flush
8
+ end
9
+
10
+ def example_pending(example)
11
+ super(example)
12
+ output.puts pending_output(example, example.execution_result[:pending_message])
13
+ output.flush
14
+ end
15
+
16
+ def example_failed(example)
17
+ super(example)
18
+ output.puts failure_output(example, example.execution_result[:exception])
19
+ output.flush
20
+ end
21
+
22
+ private
23
+
24
+ def passed_output(example)
25
+ success_color("#{example.full_description.strip}")
26
+ end
27
+
28
+ def pending_output(example, message)
29
+ pending_color("#{example.full_description.strip} (PENDING: #{message})")
30
+ end
31
+
32
+ def failure_output(example, exception)
33
+ failure_color("#{example.full_description.strip} (FAILED - #{next_failure_index})")
34
+ end
35
+
36
+ def next_failure_index
37
+ @next_failure_index ||= 0
38
+ @next_failure_index += 1
39
+ end
40
+ end
@@ -0,0 +1,57 @@
1
+ require File.expand_path('../spec_suite_configuration', __FILE__)
2
+
3
+ require 'ostruct'
4
+
5
+ class DefinesSpecSuiteTasks
6
+ extend Rake::DSL
7
+
8
+ def self.configuration
9
+ @configuration ||= SpecSuiteConfiguration.build
10
+ end
11
+
12
+ def self.call
13
+ desc 'Run all tests'
14
+ task :spec do
15
+ results = []
16
+ DefinesSpecSuiteTasks.configuration.each_matching_suite.each do |suite|
17
+ puts "=== Running #{suite.desc} tests ================================================"
18
+ results << suite.run
19
+ puts
20
+ end
21
+ if results.any? { |result| not result.success? }
22
+ raise 'Spec suite failed!'
23
+ end
24
+ end
25
+
26
+ namespace :spec do
27
+ DefinesSpecSuiteTasks.configuration.each_matching_suite do |suite|
28
+ desc "Run #{suite.desc} tests"
29
+ task suite.name => "appraisal:#{suite.appraisal_name}:install" do
30
+ result = suite.run
31
+ if not result.success?
32
+ raise "#{suite.desc} suite failed!"
33
+ end
34
+ end
35
+ end
36
+
37
+ require 'rspec/core/rake_task'
38
+
39
+ desc "Run the unit tests"
40
+ RSpec::Core::RakeTask.new(:unit) do |t|
41
+ t.pattern = 'spec/suites/rspec_2/unit/**/*_spec.rb'
42
+ end
43
+
44
+ desc "Run the functional (API) tests"
45
+ RSpec::Core::RakeTask.new(:functional) do |t|
46
+ t.pattern = 'spec/suites/rspec_2/functional/**/*_spec.rb'
47
+ end
48
+ end
49
+
50
+ namespace :travis do
51
+ desc 'Regenerate .travis.yml'
52
+ task :regenerate_config do
53
+ DefinesSpecSuiteTasks.configuration.generate_travis_config
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,598 @@
1
+ require 'rails/gem_dependency'
2
+
3
+ module Gem
4
+ ## Copied from RubyGems 1.3.7 (Ruby 1.9.2)
5
+ class SourceIndex
6
+ include Enumerable
7
+
8
+ attr_reader :gems # :nodoc:
9
+
10
+ ##
11
+ # Directories to use to refresh this SourceIndex when calling refresh!
12
+
13
+ attr_accessor :spec_dirs
14
+
15
+ class << self
16
+ ##
17
+ # Factory method to construct a source index instance for a given
18
+ # path.
19
+ #
20
+ # deprecated::
21
+ # If supplied, from_installed_gems will act just like
22
+ # +from_gems_in+. This argument is deprecated and is provided
23
+ # just for backwards compatibility, and should not generally
24
+ # be used.
25
+ #
26
+ # return::
27
+ # SourceIndex instance
28
+
29
+ def from_installed_gems(*deprecated)
30
+ if deprecated.empty?
31
+ from_gems_in(*installed_spec_directories)
32
+ else
33
+ from_gems_in(*deprecated) # HACK warn
34
+ end
35
+ end
36
+
37
+ ##
38
+ # Returns a list of directories from Gem.path that contain specifications.
39
+
40
+ def installed_spec_directories
41
+ Gem.path.collect { |dir| File.join(dir, "specifications") }
42
+ end
43
+
44
+ ##
45
+ # Creates a new SourceIndex from the ruby format gem specifications in
46
+ # +spec_dirs+.
47
+
48
+ def from_gems_in(*spec_dirs)
49
+ source_index = new
50
+ source_index.spec_dirs = spec_dirs
51
+ source_index.refresh!
52
+ end
53
+
54
+ ##
55
+ # Loads a ruby-format specification from +file_name+ and returns the
56
+ # loaded spec.
57
+
58
+ def load_specification(file_name)
59
+ return nil unless file_name and File.exist? file_name
60
+
61
+ spec_code = if defined? Encoding then
62
+ File.read file_name, :encoding => 'UTF-8'
63
+ else
64
+ File.read file_name
65
+ end.untaint
66
+
67
+ begin
68
+ gemspec = eval spec_code, binding, file_name
69
+
70
+ if gemspec.is_a?(Gem::Specification)
71
+ gemspec.loaded_from = file_name
72
+ return gemspec
73
+ end
74
+ alert_warning "File '#{file_name}' does not evaluate to a gem specification"
75
+ rescue SignalException, SystemExit
76
+ raise
77
+ rescue SyntaxError => e
78
+ alert_warning e
79
+ alert_warning spec_code
80
+ rescue Exception => e
81
+ alert_warning "#{e.inspect}\n#{spec_code}"
82
+ alert_warning "Invalid .gemspec format in '#{file_name}'"
83
+ end
84
+
85
+ return nil
86
+ end
87
+
88
+ end
89
+
90
+ ##
91
+ # Constructs a source index instance from the provided specifications, which
92
+ # is a Hash of gem full names and Gem::Specifications.
93
+ #--
94
+ # TODO merge @gems and @prerelease_gems and provide a separate method
95
+ # #prerelease_gems
96
+
97
+ def initialize(specifications={})
98
+ @gems = {}
99
+ specifications.each{ |full_name, spec| add_spec spec }
100
+ @spec_dirs = nil
101
+ end
102
+
103
+ # TODO: remove method
104
+ def all_gems
105
+ @gems
106
+ end
107
+
108
+ def prerelease_gems
109
+ @gems.reject{ |name, gem| !gem.version.prerelease? }
110
+ end
111
+
112
+ def released_gems
113
+ @gems.reject{ |name, gem| gem.version.prerelease? }
114
+ end
115
+
116
+ ##
117
+ # Reconstruct the source index from the specifications in +spec_dirs+.
118
+
119
+ def load_gems_in(*spec_dirs)
120
+ @gems.clear
121
+
122
+ spec_dirs.reverse_each do |spec_dir|
123
+ spec_files = Dir.glob File.join(spec_dir, '*.gemspec')
124
+
125
+ spec_files.each do |spec_file|
126
+ gemspec = self.class.load_specification spec_file.untaint
127
+ add_spec gemspec if gemspec
128
+ end
129
+ end
130
+
131
+ self
132
+ end
133
+
134
+ ##
135
+ # Returns an Array specifications for the latest released versions
136
+ # of each gem in this index.
137
+
138
+ def latest_specs
139
+ result = Hash.new { |h,k| h[k] = [] }
140
+ latest = {}
141
+
142
+ sort.each do |_, spec|
143
+ name = spec.name
144
+ curr_ver = spec.version
145
+ prev_ver = latest.key?(name) ? latest[name].version : nil
146
+
147
+ next if curr_ver.prerelease?
148
+ next unless prev_ver.nil? or curr_ver >= prev_ver or
149
+ latest[name].platform != Gem::Platform::RUBY
150
+
151
+ if prev_ver.nil? or
152
+ (curr_ver > prev_ver and spec.platform == Gem::Platform::RUBY) then
153
+ result[name].clear
154
+ latest[name] = spec
155
+ end
156
+
157
+ if spec.platform != Gem::Platform::RUBY then
158
+ result[name].delete_if do |result_spec|
159
+ result_spec.platform == spec.platform
160
+ end
161
+ end
162
+
163
+ result[name] << spec
164
+ end
165
+
166
+ # TODO: why is this a hash while @gems is an array? Seems like
167
+ # structural similarity would be good.
168
+ result.values.flatten
169
+ end
170
+
171
+ ##
172
+ # An array including only the prerelease gemspecs
173
+
174
+ def prerelease_specs
175
+ prerelease_gems.values
176
+ end
177
+
178
+ ##
179
+ # An array including only the released gemspecs
180
+
181
+ def released_specs
182
+ released_gems.values
183
+ end
184
+
185
+ ##
186
+ # Add a gem specification to the source index.
187
+
188
+ def add_spec(gem_spec, name = gem_spec.full_name)
189
+ # No idea why, but the Indexer wants to insert them using original_name
190
+ # instead of full_name. So we make it an optional arg.
191
+ @gems[name] = gem_spec
192
+ end
193
+
194
+ ##
195
+ # Add gem specifications to the source index.
196
+
197
+ def add_specs(*gem_specs)
198
+ gem_specs.each do |spec|
199
+ add_spec spec
200
+ end
201
+ end
202
+
203
+ ##
204
+ # Remove a gem specification named +full_name+.
205
+
206
+ def remove_spec(full_name)
207
+ @gems.delete full_name
208
+ end
209
+
210
+ ##
211
+ # Iterate over the specifications in the source index.
212
+
213
+ def each(&block) # :yields: gem.full_name, gem
214
+ @gems.each(&block)
215
+ end
216
+
217
+ ##
218
+ # The gem specification given a full gem spec name.
219
+
220
+ def specification(full_name)
221
+ @gems[full_name]
222
+ end
223
+
224
+ ##
225
+ # The signature for the source index. Changes in the signature indicate a
226
+ # change in the index.
227
+
228
+ def index_signature
229
+ require 'digest'
230
+
231
+ Digest::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
232
+ end
233
+
234
+ ##
235
+ # The signature for the given gem specification.
236
+
237
+ def gem_signature(gem_full_name)
238
+ require 'digest'
239
+
240
+ Digest::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
241
+ end
242
+
243
+ def size
244
+ @gems.size
245
+ end
246
+ alias length size
247
+
248
+ ##
249
+ # Find a gem by an exact match on the short name.
250
+
251
+ def find_name(gem_name, version_requirement = Gem::Requirement.default)
252
+ dep = Gem::Dependency.new gem_name, version_requirement
253
+ search dep
254
+ end
255
+
256
+ ##
257
+ # Search for a gem by Gem::Dependency +gem_pattern+. If +only_platform+
258
+ # is true, only gems matching Gem::Platform.local will be returned. An
259
+ # Array of matching Gem::Specification objects is returned.
260
+ #
261
+ # For backwards compatibility, a String or Regexp pattern may be passed as
262
+ # +gem_pattern+, and a Gem::Requirement for +platform_only+. This
263
+ # behavior is deprecated and will be removed.
264
+
265
+ def search(gem_pattern, platform_only = false)
266
+ version_requirement = nil
267
+ only_platform = false
268
+
269
+ # TODO - Remove support and warning for legacy arguments after 2008/11
270
+ unless Gem::Dependency === gem_pattern
271
+ warn "#{Gem.location_of_caller.join ':'}:Warning: Gem::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated, use #find_name"
272
+ end
273
+
274
+ case gem_pattern
275
+ when Regexp then
276
+ version_requirement = platform_only || Gem::Requirement.default
277
+ when Gem::Dependency then
278
+ only_platform = platform_only
279
+ version_requirement = gem_pattern.requirement
280
+ gem_pattern = if Regexp === gem_pattern.name then
281
+ gem_pattern.name
282
+ elsif gem_pattern.name.empty? then
283
+ //
284
+ else
285
+ /^#{Regexp.escape gem_pattern.name}$/
286
+ end
287
+ else
288
+ version_requirement = platform_only || Gem::Requirement.default
289
+ gem_pattern = /#{gem_pattern}/i
290
+ end
291
+
292
+ unless Gem::Requirement === version_requirement then
293
+ version_requirement = Gem::Requirement.create version_requirement
294
+ end
295
+
296
+ specs = all_gems.values.select do |spec|
297
+ spec.name =~ gem_pattern and
298
+ version_requirement.satisfied_by? spec.version
299
+ end
300
+
301
+ if only_platform then
302
+ specs = specs.select do |spec|
303
+ Gem::Platform.match spec.platform
304
+ end
305
+ end
306
+
307
+ specs.sort_by { |s| s.sort_obj }
308
+ end
309
+
310
+ ##
311
+ # Replaces the gems in the source index from specifications in the
312
+ # directories this source index was created from. Raises an exception if
313
+ # this source index wasn't created from a directory (via from_gems_in or
314
+ # from_installed_gems, or having spec_dirs set).
315
+
316
+ def refresh!
317
+ raise 'source index not created from disk' if @spec_dirs.nil?
318
+ load_gems_in(*@spec_dirs)
319
+ end
320
+
321
+ ##
322
+ # Returns an Array of Gem::Specifications that are not up to date.
323
+
324
+ def outdated
325
+ outdateds = []
326
+
327
+ latest_specs.each do |local|
328
+ dependency = Gem::Dependency.new local.name, ">= #{local.version}"
329
+
330
+ begin
331
+ fetcher = Gem::SpecFetcher.fetcher
332
+ remotes = fetcher.find_matching dependency
333
+ remotes = remotes.map { |(name, version,_),_| version }
334
+ rescue Gem::RemoteFetcher::FetchError => e
335
+ raise unless fetcher.warn_legacy e do
336
+ require 'rubygems/source_info_cache'
337
+
338
+ specs = Gem::SourceInfoCache.search_with_source dependency, true
339
+
340
+ remotes = specs.map { |spec,| spec.version }
341
+ end
342
+ end
343
+
344
+ latest = remotes.sort.last
345
+
346
+ outdateds << local.name if latest and local.version < latest
347
+ end
348
+
349
+ outdateds
350
+ end
351
+
352
+ ##
353
+ # Updates this SourceIndex from +source_uri+. If +all+ is false, only the
354
+ # latest gems are fetched.
355
+
356
+ def update(source_uri, all)
357
+ source_uri = URI.parse source_uri unless URI::Generic === source_uri
358
+ source_uri.path += '/' unless source_uri.path =~ /\/$/
359
+
360
+ use_incremental = false
361
+
362
+ begin
363
+ gem_names = fetch_quick_index source_uri, all
364
+ remove_extra gem_names
365
+ missing_gems = find_missing gem_names
366
+
367
+ return false if missing_gems.size.zero?
368
+
369
+ say "Missing metadata for #{missing_gems.size} gems" if
370
+ missing_gems.size > 0 and Gem.configuration.really_verbose
371
+
372
+ use_incremental = missing_gems.size <= Gem.configuration.bulk_threshold
373
+ rescue Gem::OperationNotSupportedError => ex
374
+ alert_error "Falling back to bulk fetch: #{ex.message}" if
375
+ Gem.configuration.really_verbose
376
+ use_incremental = false
377
+ end
378
+
379
+ if use_incremental then
380
+ update_with_missing(source_uri, missing_gems)
381
+ else
382
+ new_index = fetch_bulk_index(source_uri)
383
+ @gems.replace(new_index.gems)
384
+ end
385
+
386
+ true
387
+ end
388
+
389
+ def ==(other) # :nodoc:
390
+ self.class === other and @gems == other.gems
391
+ end
392
+
393
+ def dump
394
+ Marshal.dump(self)
395
+ end
396
+
397
+ private
398
+
399
+ def fetcher
400
+ require 'rubygems/remote_fetcher'
401
+
402
+ Gem::RemoteFetcher.fetcher
403
+ end
404
+
405
+ def fetch_index_from(source_uri)
406
+ @fetch_error = nil
407
+
408
+ indexes = %W[
409
+ Marshal.#{Gem.marshal_version}.Z
410
+ Marshal.#{Gem.marshal_version}
411
+ yaml.Z
412
+ yaml
413
+ ]
414
+
415
+ indexes.each do |name|
416
+ spec_data = nil
417
+ index = source_uri + name
418
+ begin
419
+ spec_data = fetcher.fetch_path index
420
+ spec_data = unzip(spec_data) if name =~ /\.Z$/
421
+
422
+ if name =~ /Marshal/ then
423
+ return Marshal.load(spec_data)
424
+ else
425
+ return YAML.load(spec_data)
426
+ end
427
+ rescue => e
428
+ if Gem.configuration.really_verbose then
429
+ alert_error "Unable to fetch #{name}: #{e.message}"
430
+ end
431
+
432
+ @fetch_error = e
433
+ end
434
+ end
435
+
436
+ nil
437
+ end
438
+
439
+ def fetch_bulk_index(source_uri)
440
+ say "Bulk updating Gem source index for: #{source_uri}" if
441
+ Gem.configuration.verbose
442
+
443
+ index = fetch_index_from(source_uri)
444
+ if index.nil? then
445
+ raise Gem::RemoteSourceException,
446
+ "Error fetching remote gem cache: #{@fetch_error}"
447
+ end
448
+ @fetch_error = nil
449
+ index
450
+ end
451
+
452
+ ##
453
+ # Get the quick index needed for incremental updates.
454
+
455
+ def fetch_quick_index(source_uri, all)
456
+ index = all ? 'index' : 'latest_index'
457
+
458
+ zipped_index = fetcher.fetch_path source_uri + "quick/#{index}.rz"
459
+
460
+ unzip(zipped_index).split("\n")
461
+ rescue ::Exception => e
462
+ unless all then
463
+ say "Latest index not found, using quick index" if
464
+ Gem.configuration.really_verbose
465
+
466
+ fetch_quick_index source_uri, true
467
+ else
468
+ raise Gem::OperationNotSupportedError,
469
+ "No quick index found: #{e.message}"
470
+ end
471
+ end
472
+
473
+ ##
474
+ # Make a list of full names for all the missing gemspecs.
475
+
476
+ def find_missing(spec_names)
477
+ unless defined? @originals then
478
+ @originals = {}
479
+ each do |full_name, spec|
480
+ @originals[spec.original_name] = spec
481
+ end
482
+ end
483
+
484
+ spec_names.find_all { |full_name|
485
+ @originals[full_name].nil?
486
+ }
487
+ end
488
+
489
+ def remove_extra(spec_names)
490
+ dictionary = spec_names.inject({}) { |h, k| h[k] = true; h }
491
+ each do |name, spec|
492
+ remove_spec name unless dictionary.include? spec.original_name
493
+ end
494
+ end
495
+
496
+ ##
497
+ # Unzip the given string.
498
+
499
+ def unzip(string)
500
+ require 'zlib'
501
+ Gem.inflate string
502
+ end
503
+
504
+ ##
505
+ # Tries to fetch Marshal representation first, then YAML
506
+
507
+ def fetch_single_spec(source_uri, spec_name)
508
+ @fetch_error = nil
509
+
510
+ begin
511
+ marshal_uri = source_uri + "quick/Marshal.#{Gem.marshal_version}/#{spec_name}.gemspec.rz"
512
+ zipped = fetcher.fetch_path marshal_uri
513
+ return Marshal.load(unzip(zipped))
514
+ rescue => ex
515
+ @fetch_error = ex
516
+
517
+ if Gem.configuration.really_verbose then
518
+ say "unable to fetch marshal gemspec #{marshal_uri}: #{ex.class} - #{ex}"
519
+ end
520
+ end
521
+
522
+ begin
523
+ yaml_uri = source_uri + "quick/#{spec_name}.gemspec.rz"
524
+ zipped = fetcher.fetch_path yaml_uri
525
+ return YAML.load(unzip(zipped))
526
+ rescue => ex
527
+ @fetch_error = ex
528
+ if Gem.configuration.really_verbose then
529
+ say "unable to fetch YAML gemspec #{yaml_uri}: #{ex.class} - #{ex}"
530
+ end
531
+ end
532
+
533
+ nil
534
+ end
535
+
536
+ ##
537
+ # Update the cached source index with the missing names.
538
+
539
+ def update_with_missing(source_uri, missing_names)
540
+ progress = ui.progress_reporter(missing_names.size,
541
+ "Updating metadata for #{missing_names.size} gems from #{source_uri}")
542
+ missing_names.each do |spec_name|
543
+ gemspec = fetch_single_spec(source_uri, spec_name)
544
+ if gemspec.nil? then
545
+ ui.say "Failed to download spec #{spec_name} from #{source_uri}:\n" \
546
+ "\t#{@fetch_error.message}"
547
+ else
548
+ add_spec gemspec
549
+ progress.updated spec_name
550
+ end
551
+ @fetch_error = nil
552
+ end
553
+ progress.done
554
+ progress.count
555
+ end
556
+ end
557
+
558
+ class FakeSourceIndex
559
+ include Enumerable
560
+
561
+ def initialize(specs_by_filename = {})
562
+ @specs_by_filename = specs_by_filename
563
+ end
564
+
565
+ def search(dep)
566
+ Specification.find_all_by_name(dep.name, dep.requirement)
567
+ end
568
+
569
+ def each
570
+ Specification.each do |spec|
571
+ yield spec.name, spec
572
+ end
573
+ end
574
+ end
575
+
576
+ class Specification
577
+ alias_method :installation_path, :base_dir
578
+ end
579
+
580
+ class << self
581
+ attr_accessor :source_index
582
+ alias_method :cache, :source_index
583
+
584
+ ## Copied from RubyGems 1.3.7 (Ruby 1.9.2)
585
+ def available?(gem, *requirements)
586
+ requirements = Gem::Requirement.default if requirements.empty?
587
+
588
+ unless gem.respond_to?(:name) and
589
+ gem.respond_to?(:requirement) then
590
+ gem = Gem::Dependency.new gem, requirements
591
+ end
592
+
593
+ !Gem.source_index.search(gem).empty?
594
+ end
595
+ end
596
+
597
+ self.source_index = FakeSourceIndex.new
598
+ end