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.
- checksums.yaml +5 -5
- data/Appraisals +6 -0
- data/CHANGES.md +102 -1
- data/CREDITS.md +5 -0
- data/Gemfile +3 -0
- data/README.md +91 -110
- data/Rakefile +43 -0
- data/doc/02_syntax_comparison.md +1 -0
- data/gemfiles/ruby_19_rspec_2.gemfile +14 -0
- data/gemfiles/ruby_19_rspec_2.gemfile.lock +49 -0
- data/gemfiles/ruby_19_rspec_2_rails_4.gemfile +15 -0
- data/gemfiles/ruby_19_rspec_2_rails_4.gemfile.lock +119 -0
- data/lib/rr/class_instance_method_defined.rb +1 -1
- data/lib/rr/core_ext/array.rb +2 -0
- data/lib/rr/core_ext/hash.rb +2 -0
- data/lib/rr/deprecations.rb +97 -0
- data/lib/rr/double.rb +28 -10
- data/lib/rr/double_definitions/double_definition.rb +39 -16
- data/lib/rr/double_definitions/double_definition_create.rb +5 -5
- data/lib/rr/double_definitions/double_definition_create_blank_slate.rb +10 -4
- data/lib/rr/double_definitions/double_injections/any_instance_of.rb +1 -1
- data/lib/rr/double_definitions/double_injections/instance.rb +2 -2
- data/lib/rr/double_definitions/strategies/strategy.rb +27 -8
- data/lib/rr/double_definitions/strategies/verification/mock.rb +8 -2
- data/lib/rr/double_matches.rb +4 -3
- data/lib/rr/dsl.rb +152 -0
- data/lib/rr/expectations/any_argument_expectation.rb +4 -4
- data/lib/rr/expectations/argument_equality_expectation.rb +43 -5
- data/lib/rr/injections/double_injection.rb +67 -19
- data/lib/rr/injections/method_missing_injection.rb +37 -6
- data/lib/rr/integrations.rb +13 -12
- data/lib/rr/integrations/decorator.rb +4 -1
- data/lib/rr/integrations/minitest_4.rb +1 -1
- data/lib/rr/integrations/minitest_4_active_support.rb +1 -1
- data/lib/rr/integrations/rspec/invocation_matcher.rb +0 -8
- data/lib/rr/integrations/rspec_2.rb +28 -3
- data/lib/rr/keyword_arguments.rb +15 -0
- data/lib/rr/method_dispatches/base_method_dispatch.rb +22 -5
- data/lib/rr/method_dispatches/method_dispatch.rb +21 -10
- data/lib/rr/method_dispatches/method_missing_dispatch.rb +14 -5
- data/lib/rr/recorded_call.rb +35 -0
- data/lib/rr/recorded_calls.rb +23 -9
- data/lib/rr/space.rb +15 -5
- data/lib/rr/spy_verification.rb +13 -5
- data/lib/rr/version.rb +1 -2
- data/lib/rr/wildcard_matchers.rb +10 -10
- data/lib/rr/without_autohook.rb +7 -14
- data/rr.gemspec +14 -5
- data/spec/custom_formatter_for_rspec.rb +18 -0
- data/spec/custom_formatter_for_rspec_2.rb +40 -0
- data/spec/defines_spec_suite_tasks.rb +57 -0
- data/spec/fixtures/rubygems_patch_for_187.rb +598 -0
- data/spec/global_helper.rb +38 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_suite_configuration.rb +126 -0
- data/spec/spec_suite_runner.rb +47 -0
- data/spec/suites.yml +10 -0
- data/spec/suites/rspec_2/functional/any_instance_of_spec.rb +147 -0
- data/spec/suites/rspec_2/functional/dont_allow_spec.rb +17 -0
- data/spec/suites/rspec_2/functional/mock_bang_spec.rb +20 -0
- data/spec/suites/rspec_2/functional/mock_instance_of_spec.rb +14 -0
- data/spec/suites/rspec_2/functional/mock_instance_of_strong_spec.rb +15 -0
- data/spec/suites/rspec_2/functional/mock_proxy_instance_of_spec.rb +15 -0
- data/spec/suites/rspec_2/functional/mock_proxy_spec.rb +14 -0
- data/spec/suites/rspec_2/functional/mock_spec.rb +17 -0
- data/spec/suites/rspec_2/functional/mock_strong_spec.rb +14 -0
- data/spec/suites/rspec_2/functional/received_spec.rb +16 -0
- data/spec/suites/rspec_2/functional/spy_spec.rb +102 -0
- data/spec/suites/rspec_2/functional/stub_bang_spec.rb +20 -0
- data/spec/suites/rspec_2/functional/stub_instance_of_spec.rb +15 -0
- data/spec/suites/rspec_2/functional/stub_instance_of_strong_spec.rb +15 -0
- data/spec/suites/rspec_2/functional/stub_proxy_instance_of_spec.rb +16 -0
- data/spec/suites/rspec_2/functional/stub_proxy_spec.rb +45 -0
- data/spec/suites/rspec_2/functional/stub_spec.rb +71 -0
- data/spec/suites/rspec_2/functional/stub_strong_spec.rb +15 -0
- data/spec/suites/rspec_2/functional/wildcard_matchers_spec.rb +128 -0
- data/spec/suites/rspec_2/helper.rb +28 -0
- data/spec/suites/rspec_2/integration/minitest_4_spec.rb +109 -0
- data/spec/suites/rspec_2/integration/minitest_spec.rb +109 -0
- data/spec/suites/rspec_2/spec_helper.rb +3 -0
- data/spec/suites/rspec_2/support/matchers/wildcard_matcher_matchers.rb +32 -0
- data/spec/suites/rspec_2/support/mixins/double_definition_creator_helpers.rb +173 -0
- data/spec/suites/rspec_2/support/mixins/mock_definition_creator_helpers.rb +45 -0
- data/spec/suites/rspec_2/support/mixins/proxy_definition_creator_helpers.rb +33 -0
- data/spec/suites/rspec_2/support/mixins/stub_creator_helpers.rb +43 -0
- data/spec/suites/rspec_2/support/mixins/stub_definition_creator_helpers.rb +45 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/argument_expectations_with_never_called_qualifier.rb +39 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/argument_expectations_with_times_called_qualifier.rb +50 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/argument_expectations_without_qualifiers.rb +131 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/dont_allow.rb +148 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_instance_of.rb +26 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_instance_of_strong.rb +28 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_proxy.rb +11 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_strong.rb +37 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mocking.rb +107 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_instance_of.rb +32 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_instance_of_strong.rb +39 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_proxy.rb +11 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_strong.rb +37 -0
- data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stubbing.rb +57 -0
- data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/array_flatten_bug.rb +35 -0
- data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/block_form.rb +31 -0
- data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/comparing_arity.rb +63 -0
- data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/object_is_proxy.rb +43 -0
- data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/sequential_invocations.rb +26 -0
- data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/setting_implementation.rb +51 -0
- data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/yields.rb +81 -0
- data/spec/suites/rspec_2/support/shared_examples/space.rb +13 -0
- data/spec/suites/rspec_2/support/shared_examples/times_called_expectation.rb +9 -0
- data/spec/suites/rspec_2/unit/core_ext/array_spec.rb +39 -0
- data/spec/suites/rspec_2/unit/core_ext/enumerable_spec.rb +53 -0
- data/spec/suites/rspec_2/unit/core_ext/hash_spec.rb +55 -0
- data/spec/suites/rspec_2/unit/core_ext/range_spec.rb +41 -0
- data/spec/suites/rspec_2/unit/core_ext/regexp_spec.rb +41 -0
- data/spec/suites/rspec_2/unit/deprecations_spec.rb +27 -0
- data/spec/suites/rspec_2/unit/double_definitions/child_double_definition_create_spec.rb +114 -0
- data/spec/suites/rspec_2/unit/double_definitions/double_definition_create_blank_slate_spec.rb +93 -0
- data/spec/suites/rspec_2/unit/double_definitions/double_definition_create_spec.rb +446 -0
- data/spec/suites/rspec_2/unit/dsl/double_creators_spec.rb +133 -0
- data/spec/suites/rspec_2/unit/dsl/space_spec.rb +99 -0
- data/spec/suites/rspec_2/unit/dsl/wildcard_matchers_spec.rb +67 -0
- data/spec/suites/rspec_2/unit/errors/rr_error_spec.rb +67 -0
- data/spec/suites/rspec_2/unit/expectations/any_argument_expectation_spec.rb +48 -0
- data/spec/suites/rspec_2/unit/expectations/anything_argument_equality_expectation_spec.rb +14 -0
- data/spec/suites/rspec_2/unit/expectations/argument_equality_expectation_spec.rb +135 -0
- data/spec/suites/rspec_2/unit/expectations/boolean_argument_equality_expectation_spec.rb +30 -0
- data/spec/suites/rspec_2/unit/expectations/hash_including_argument_equality_expectation_spec.rb +92 -0
- data/spec/suites/rspec_2/unit/expectations/satisfy_argument_equality_expectation_spec.rb +61 -0
- data/spec/suites/rspec_2/unit/expectations/times_called_expectation/any_times_matcher_spec.rb +22 -0
- data/spec/suites/rspec_2/unit/expectations/times_called_expectation/at_least_matcher_spec.rb +37 -0
- data/spec/suites/rspec_2/unit/expectations/times_called_expectation/at_most_matcher_spec.rb +43 -0
- data/spec/suites/rspec_2/unit/expectations/times_called_expectation/integer_matcher_spec.rb +58 -0
- data/spec/suites/rspec_2/unit/expectations/times_called_expectation/proc_matcher_spec.rb +35 -0
- data/spec/suites/rspec_2/unit/expectations/times_called_expectation/range_matcher_spec.rb +39 -0
- data/spec/suites/rspec_2/unit/hash_with_object_id_key_spec.rb +88 -0
- data/spec/suites/rspec_2/unit/injections/double_injection/double_injection_spec.rb +533 -0
- data/spec/suites/rspec_2/unit/injections/double_injection/double_injection_verify_spec.rb +32 -0
- data/spec/suites/rspec_2/unit/integrations/rspec/invocation_matcher_spec.rb +297 -0
- data/spec/suites/rspec_2/unit/integrations/rspec_spec.rb +70 -0
- data/spec/suites/rspec_2/unit/rr_spec.rb +28 -0
- data/spec/suites/rspec_2/unit/space_spec.rb +598 -0
- data/spec/suites/rspec_2/unit/spy_verification_spec.rb +133 -0
- data/spec/suites/rspec_2/unit/times_called_matchers/any_times_matcher_spec.rb +46 -0
- data/spec/suites/rspec_2/unit/times_called_matchers/at_least_matcher_spec.rb +54 -0
- data/spec/suites/rspec_2/unit/times_called_matchers/at_most_matcher_spec.rb +69 -0
- data/spec/suites/rspec_2/unit/times_called_matchers/integer_matcher_spec.rb +69 -0
- data/spec/suites/rspec_2/unit/times_called_matchers/proc_matcher_spec.rb +54 -0
- data/spec/suites/rspec_2/unit/times_called_matchers/range_matcher_spec.rb +75 -0
- data/spec/suites/rspec_2/unit/times_called_matchers/times_called_matcher_spec.rb +117 -0
- data/spec/suites/rspec_2/unit/wildcard_matchers/anything_spec.rb +33 -0
- data/spec/suites/rspec_2/unit/wildcard_matchers/boolean_spec.rb +45 -0
- data/spec/suites/rspec_2/unit/wildcard_matchers/duck_type_spec.rb +64 -0
- data/spec/suites/rspec_2/unit/wildcard_matchers/hash_including_spec.rb +64 -0
- data/spec/suites/rspec_2/unit/wildcard_matchers/is_a_spec.rb +55 -0
- data/spec/suites/rspec_2/unit/wildcard_matchers/numeric_spec.rb +46 -0
- data/spec/suites/rspec_2/unit/wildcard_matchers/satisfy_spec.rb +57 -0
- data/spec/support/adapter.rb +22 -0
- data/spec/support/adapter_tests/base.rb +45 -0
- data/spec/support/adapter_tests/minitest.rb +7 -0
- data/spec/support/adapter_tests/rspec.rb +70 -0
- data/spec/support/adapter_tests/test_unit.rb +47 -0
- data/spec/support/command_runner.rb +105 -0
- data/spec/support/generator.rb +56 -0
- data/spec/support/integration_tests/base.rb +64 -0
- data/spec/support/integration_tests/rails.rb +60 -0
- data/spec/support/integration_tests/rails_minitest.rb +13 -0
- data/spec/support/integration_tests/rails_rspec.rb +13 -0
- data/spec/support/integration_tests/rails_test_unit.rb +13 -0
- data/spec/support/integration_tests/rails_test_unit_like.rb +13 -0
- data/spec/support/integration_tests/ruby.rb +7 -0
- data/spec/support/integration_tests/ruby_minitest.rb +13 -0
- data/spec/support/integration_tests/ruby_rspec.rb +13 -0
- data/spec/support/integration_tests/ruby_test_unit.rb +13 -0
- data/spec/support/matchers/be_a_subset_of_matcher.rb +24 -0
- data/spec/support/project/cucumber.rb +50 -0
- data/spec/support/project/generator.rb +348 -0
- data/spec/support/project/minitest.rb +39 -0
- data/spec/support/project/rails.rb +199 -0
- data/spec/support/project/rails_minitest.rb +17 -0
- data/spec/support/project/rails_rspec.rb +50 -0
- data/spec/support/project/rails_test_unit.rb +17 -0
- data/spec/support/project/rails_test_unit_like.rb +17 -0
- data/spec/support/project/rspec.rb +69 -0
- data/spec/support/project/ruby.rb +34 -0
- data/spec/support/project/ruby_minitest.rb +11 -0
- data/spec/support/project/ruby_rspec.rb +29 -0
- data/spec/support/project/ruby_test_unit.rb +11 -0
- data/spec/support/project/ruby_test_unit_like.rb +21 -0
- data/spec/support/project/test_unit.rb +29 -0
- data/spec/support/project/test_unit_like.rb +7 -0
- data/spec/support/project/tests_runner.rb +22 -0
- data/spec/support/test.sqlite3 +0 -0
- data/spec/support/test_case/generator.rb +53 -0
- data/spec/support/test_case/minitest.rb +13 -0
- data/spec/support/test_case/rspec.rb +19 -0
- data/spec/support/test_case/test_unit.rb +21 -0
- data/spec/support/test_file/generator.rb +120 -0
- data/spec/support/test_file/minitest.rb +19 -0
- data/spec/support/test_file/rails_minitest.rb +7 -0
- data/spec/support/test_file/rails_rspec.rb +12 -0
- data/spec/support/test_file/rails_test_unit.rb +25 -0
- data/spec/support/test_file/rspec.rb +33 -0
- data/spec/support/test_file/test_unit.rb +36 -0
- data/spec/support/test_helper/generator.rb +27 -0
- data/spec/support/test_helper/minitest.rb +7 -0
- data/spec/support/test_helper/rails.rb +31 -0
- data/spec/support/test_helper/rails_minitest.rb +7 -0
- data/spec/support/test_helper/rails_rspec.rb +25 -0
- data/spec/support/test_helper/rails_test_unit.rb +23 -0
- data/spec/support/test_helper/rspec.rb +7 -0
- data/spec/support/test_helper/ruby.rb +31 -0
- data/spec/support/test_helper/test_unit.rb +7 -0
- metadata +240 -19
- data/VERSION +0 -1
- data/lib/rr/adapters.rb +0 -44
- data/lib/rr/adapters/rr_methods.rb +0 -142
- data/lib/rr/integrations/rspec_1.rb +0 -46
- data/lib/rr/integrations/test_unit_1.rb +0 -63
- data/lib/rr/integrations/test_unit_2.rb +0 -15
- data/lib/rr/integrations/test_unit_200.rb +0 -27
- data/lib/rr/integrations/test_unit_200_active_support.rb +0 -25
- data/lib/rr/integrations/test_unit_2_active_support.rb +0 -38
- 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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
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
|
data/lib/rr/spy_verification.rb
CHANGED
|
@@ -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
data/lib/rr/wildcard_matchers.rb
CHANGED
|
@@ -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::
|
|
109
|
-
|
|
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::
|
|
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::
|
|
148
|
+
|
|
149
|
+
module RR::DSL
|
|
150
150
|
def divisible_by(expected_divisor)
|
|
151
151
|
RR::WildcardMatchers::DivisibleBy.new(expected_divisor)
|
|
152
152
|
end
|
data/lib/rr/without_autohook.rb
CHANGED
|
@@ -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/
|
|
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
|
-
|
|
99
|
-
require 'rr/
|
|
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
|
|
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 = ['
|
|
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 = '
|
|
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
|
-
'
|
|
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
|