pax_global_header00006660000000000000000000000064122572424230014515gustar00rootroot0000000000000052 comment=9716067db8f909a943f1c04a54e0bec1bd8451e8 ruby-equalizer-0.0.9/000077500000000000000000000000001225724242300145035ustar00rootroot00000000000000ruby-equalizer-0.0.9/.gitignore000066400000000000000000000004071225724242300164740ustar00rootroot00000000000000## MAC OS .DS_Store ## TEXTMATE *.tmproj tmtags ## EMACS *~ \#* .\#* ## VIM *.swp ## Rubinius *.rbc .rbx ## PROJECT::GENERAL *.gem coverage profiling turbulence rdoc pkg tmp doc log .yardoc measurements ## BUNDLER .bundle Gemfile.lock ## PROJECT::SPECIFIC ruby-equalizer-0.0.9/.reek.yml000066400000000000000000000034751225724242300162430ustar00rootroot00000000000000--- Attribute: enabled: true exclude: [] BooleanParameter: enabled: true exclude: [] ClassVariable: enabled: true exclude: [] ControlParameter: enabled: true exclude: [] DataClump: enabled: true exclude: [] max_copies: 2 min_clump_size: 2 DuplicateMethodCall: enabled: true exclude: [] max_calls: 1 allow_calls: [] FeatureEnvy: enabled: true exclude: [] IrresponsibleModule: enabled: true exclude: [] LongParameterList: enabled: true exclude: [] max_params: 2 overrides: initialize: max_params: 3 LongYieldList: enabled: true exclude: [] max_params: 2 NestedIterators: enabled: true exclude: - Equalizer#define_cmp_method - Equalizer#define_hash_method - Equalizer#define_inspect_method max_allowed_nesting: 1 ignore_iterators: [] NilCheck: enabled: true exclude: [] RepeatedConditional: enabled: true exclude: [] max_ifs: 1 TooManyInstanceVariables: enabled: true exclude: [] max_instance_variables: 3 TooManyMethods: enabled: true exclude: [] max_methods: 10 TooManyStatements: enabled: true exclude: - each max_statements: 5 UncommunicativeMethodName: enabled: true exclude: [] reject: - !ruby/regexp /^[a-z]$/ - !ruby/regexp /[0-9]$/ - !ruby/regexp /[A-Z]/ accept: [] UncommunicativeModuleName: enabled: true exclude: [] reject: - !ruby/regexp /^.$/ - !ruby/regexp /[0-9]$/ accept: [] UncommunicativeParameterName: enabled: true exclude: [] reject: - !ruby/regexp /^.$/ - !ruby/regexp /[0-9]$/ - !ruby/regexp /[A-Z]/ accept: [] UncommunicativeVariableName: enabled: true exclude: [] reject: - !ruby/regexp /^.$/ - !ruby/regexp /[0-9]$/ - !ruby/regexp /[A-Z]/ accept: [] UnusedParameters: enabled: true exclude: [] UtilityFunction: enabled: true exclude: [] max_helper_calls: 0 ruby-equalizer-0.0.9/.rspec000066400000000000000000000000761225724242300156230ustar00rootroot00000000000000--color --format progress --profile --warnings --order random ruby-equalizer-0.0.9/.rubocop.yml000066400000000000000000000032621225724242300167600ustar00rootroot00000000000000AllCops: Includes: - '**/*.rake' - 'Gemfile' - 'Rakefile' Excludes: - 'vendor/**' # Avoid parameter lists longer than five parameters. ParameterLists: Max: 3 CountKeywordArgs: true # Avoid more than `Max` levels of nesting. BlockNesting: Max: 3 # Align with the style guide. CollectionMethods: PreferredMethods: collect: 'map' inject: 'reduce' find: 'detect' find_all: 'select' # Do not force public/protected/private keyword to be indented at the same # level as the def keyword. My personal preference is to outdent these keywords # because I think when scanning code it makes it easier to identify the # sections of code and visually separate them. When the keyword is at the same # level I think it sort of blends in with the def keywords and makes it harder # to scan the code and see where the sections are. AccessModifierIndentation: Enabled: false # Disable documentation checking until a class needs to be documented once Documentation: Enabled: false # Do not always use &&/|| instead of and/or. AndOr: Enabled: false # Do not favor modifier if/unless usage when you have a single-line body IfUnlessModifier: Enabled: false # Allow case equality operator (in limited use within the specs) CaseEquality: Enabled: false # Constants do not always have to use SCREAMING_SNAKE_CASE ConstantName: Enabled: false # Not all trivial readers/writers can be defined with attr_* methods TrivialAccessors: Enabled: false # Allow empty lines around body EmptyLinesAroundBody: Enabled: false # Enforce Ruby 1.8-compatible hash syntax HashSyntax: EnforcedStyle: hash_rockets # Allow dots at the end of lines DotPosition: Enabled: false ruby-equalizer-0.0.9/.ruby-gemset000066400000000000000000000000121225724242300167400ustar00rootroot00000000000000equalizer ruby-equalizer-0.0.9/.travis.yml000066400000000000000000000012371225724242300166170ustar00rootroot00000000000000language: ruby cache: bundler bundler_args: --without yard guard benchmarks script: "bundle exec rake ci" rvm: - ree - 1.8.7 - 1.9.2 - 1.9.3 - 2.0.0 - ruby-head - rbx matrix: include: - rvm: jruby-18mode env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov - rvm: jruby-19mode env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov - rvm: jruby-20mode env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov - rvm: jruby-head env: JRUBY_OPTS="$JRUBY_OPTS --debug" # for simplecov fast_finish: true notifications: irc: channels: - irc.freenode.org#rom-rb on_success: never on_failure: change ruby-equalizer-0.0.9/.yardstick.yml000066400000000000000000000000231225724242300172740ustar00rootroot00000000000000--- threshold: 100 ruby-equalizer-0.0.9/CONTRIBUTING.md000066400000000000000000000020241225724242300167320ustar00rootroot00000000000000Contributing ------------ * If you want your code merged into the mainline, please discuss the proposed changes with me before doing any work on it. This library is still in early development, and the direction it is going may not always be clear. Some features may not be appropriate yet, may need to be deferred until later when the foundation for them is laid, or may be more applicable in a plugin. * Fork the project. * Make your feature addition or bug fix. * Follow this [style guide](https://github.com/dkubb/styleguide). * Add specs for it. This is important so I don't break it in a future version unintentionally. Tests must cover all branches within the code, and code must be fully covered. * Commit, do not mess with Rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) * Run "rake ci". This must pass and not show any regressions in the metrics for the code to be merged. * Send me a pull request. Bonus points for topic branches. ruby-equalizer-0.0.9/Gemfile000066400000000000000000000007671225724242300160100ustar00rootroot00000000000000# encoding: utf-8 source 'https://rubygems.org' gem 'rake' group :test do gem 'backports' gem 'coveralls', :require => false gem 'json', :platforms => [:ruby_19] gem 'reek' gem 'rspec', '~> 2.14' gem 'rubocop', :platforms => [:ruby_19, :ruby_20] gem 'simplecov', :require => false gem 'yardstick' end platforms :jruby, :ruby_18 do gem 'mime-types', '~> 1.25' end platforms :rbx do gem 'racc' gem 'rubinius-coverage', '~> 2.0' gem 'rubysl', '~> 2.0' end gemspec ruby-equalizer-0.0.9/LICENSE000066400000000000000000000021161225724242300155100ustar00rootroot00000000000000Copyright (c) 2009-2013 Dan Kubb Copyright (c) 2012 Markus Schirp (packaging) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ruby-equalizer-0.0.9/README.md000066400000000000000000000055421225724242300157700ustar00rootroot00000000000000equalizer ========= Module to define equality, equivalence and inspection methods [![Gem Version](https://badge.fury.io/rb/equalizer.png)][gem] [![Build Status](https://secure.travis-ci.org/dkubb/equalizer.png?branch=master)][travis] [![Dependency Status](https://gemnasium.com/dkubb/equalizer.png)][gemnasium] [![Code Climate](https://codeclimate.com/github/dkubb/equalizer.png)][codeclimate] [![Coverage Status](https://coveralls.io/repos/dkubb/equalizer/badge.png?branch=master)][coveralls] [gem]: https://rubygems.org/gems/equalizer [travis]: https://travis-ci.org/dkubb/equalizer [gemnasium]: https://gemnasium.com/dkubb/equalizer [codeclimate]: https://codeclimate.com/github/dkubb/equalizer [coveralls]: https://coveralls.io/r/dkubb/equalizer Examples -------- ``` ruby class GeoLocation include Equalizer.new(:latitude, :longitude) attr_reader :latitude, :longitude def initialize(latitude, longitude) @latitude, @longitude = latitude, longitude end end point_a = GeoLocation.new(1, 2) point_b = GeoLocation.new(1, 2) point_c = GeoLocation.new(2, 2) point_a.inspect # => "#" point_a == point_b # => true point_a.hash == point_b.hash # => true point_a.eql?(point_b) # => true point_a.equal?(point_b) # => false point_a == point_c # => false point_a.hash == point_c.hash # => false point_a.eql?(point_c) # => false point_a.equal?(point_c) # => false ``` Supported Ruby Versions ----------------------- This library aims to support and is [tested against][travis] the following Ruby implementations: * Ruby 1.8.7 * Ruby 1.9.2 * Ruby 1.9.3 * Ruby 2.0.0 * [JRuby][] * [Rubinius][] * [Ruby Enterprise Edition][ree] [jruby]: http://jruby.org/ [rubinius]: http://rubini.us/ [ree]: http://www.rubyenterpriseedition.com/ If something doesn't work on one of these versions, it's a bug. This library may inadvertently work (or seem to work) on other Ruby versions or implementations, however support will only be provided for the implementations listed above. If you would like this library to support another Ruby version or implementation, you may volunteer to be a maintainer. Being a maintainer entails making sure all tests run and pass on that implementation. When something breaks on your implementation, you will be responsible for providing patches in a timely fashion. If critical issues for a particular implementation exist at the time of a major release, support for that Ruby version may be dropped. Credits ------- * Dan Kubb ([dkubb](https://github.com/dkubb)) * Piotr Solnica ([solnic](https://github.com/solnic)) * Markus Schirp ([mbj](https://github.com/mbj)) * Erik Michaels-Ober ([sferik](https://github.com/sferik)) Contributing ------------- See [CONTRIBUTING.md](CONTRIBUTING.md) for details. Copyright --------- Copyright © 2009-2013 Dan Kubb. See LICENSE for details. ruby-equalizer-0.0.9/Rakefile000066400000000000000000000014501225724242300161500ustar00rootroot00000000000000# encoding: utf-8 require 'bundler' Bundler::GemHelper.install_tasks require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) task :test => :spec task :default => :spec require 'reek/rake/task' Reek::Rake::Task.new do |reek| reek.reek_opts = '--quiet' reek.fail_on_error = true reek.config_files = '.reek.yml' end begin require 'rubocop/rake_task' Rubocop::RakeTask.new rescue LoadError desc 'Run RuboCop' task :rubocop do $stderr.puts 'Rubocop is disabled' end end require 'yardstick/rake/measurement' Yardstick::Rake::Measurement.new do |measurement| measurement.output = 'measurement/report.txt' end require 'yardstick/rake/verify' Yardstick::Rake::Verify.new do |verify| verify.threshold = 100 end task :ci => [:spec, :rubocop, :reek, :verify_measurements] ruby-equalizer-0.0.9/checksums.yaml.gz000066400000000000000000000004111225724242300177670ustar00rootroot00000000000000bReQ0sWNGddTp/ !vwv]^_r~|IVMP4R'ݭTa, DK IZ q$(.VvNh9D u9 `sU42ކ!Eو 0#q* Jzd% FeA{ \ qᲡ#0w{BsOQ03k,bipcV3+h b| آruby-equalizer-0.0.9/equalizer.gemspec000066400000000000000000000014441225724242300200540ustar00rootroot00000000000000# encoding: utf-8 require File.expand_path('../lib/equalizer/version', __FILE__) Gem::Specification.new do |gem| gem.name = 'equalizer' gem.version = Equalizer::VERSION.dup gem.authors = ['Dan Kubb', 'Markus Schirp'] gem.email = %w[dan.kubb@gmail.com mbj@schirp-dso.com] gem.description = 'Module to define equality, equivalence and inspection methods' gem.summary = gem.description gem.homepage = 'https://github.com/dkubb/equalizer' gem.licenses = 'MIT' gem.require_paths = %w[lib] gem.files = `git ls-files`.split("\n") gem.test_files = `git ls-files -- spec/{unit,integration}`.split("\n") gem.extra_rdoc_files = %w[LICENSE README.md CONTRIBUTING.md] gem.add_development_dependency('bundler', '~> 1.3', '>= 1.3.5') end ruby-equalizer-0.0.9/lib/000077500000000000000000000000001225724242300152515ustar00rootroot00000000000000ruby-equalizer-0.0.9/lib/equalizer.rb000066400000000000000000000051241225724242300176010ustar00rootroot00000000000000# encoding: utf-8 # Define equality, equivalence and inspection methods class Equalizer < Module # Initialize an Equalizer with the given keys # # Will use the keys with which it is initialized to define #cmp?, # #hash, and #inspect # # @param [Array] keys # # @return [undefined] # # @api private def initialize(*keys) @keys = keys define_methods freeze end private # Hook called when module is included # # @param [Module] descendant # the module or class including Equalizer # # @return [self] # # @api private def included(descendant) super descendant.module_eval { include Methods } end # Define the equalizer methods based on #keys # # @return [undefined] # # @api private def define_methods define_cmp_method define_hash_method define_inspect_method end # Define an #cmp? method based on the instance's values identified by #keys # # @return [undefined] # # @api private def define_cmp_method keys = @keys define_method(:cmp?) do |comparator, other| keys.all? { |key| send(key).send(comparator, other.send(key)) } end private :cmp? end # Define a #hash method based on the instance's values identified by #keys # # @return [undefined] # # @api private def define_hash_method keys = @keys define_method(:hash) do || keys.map(&method(:send)).push(self.class).hash end end # Define an inspect method that reports the values of the instance's keys # # @return [undefined] # # @api private def define_inspect_method keys = @keys define_method(:inspect) do || klass = self.class name = klass.name || klass.inspect "#<#{name}#{keys.map { |key| " #{key}=#{send(key).inspect}" }.join}>" end end # The comparison methods module Methods # Compare the object with other object for equality # # @example # object.eql?(other) # => true or false # # @param [Object] other # the other object to compare with # # @return [Boolean] # # @api public def eql?(other) instance_of?(other.class) && cmp?(__method__, other) end # Compare the object with other object for equivalency # # @example # object == other # => true or false # # @param [Object] other # the other object to compare with # # @return [Boolean] # # @api public def ==(other) other = coerce(other) if respond_to?(:coerce, true) other.kind_of?(self.class) && cmp?(__method__, other) end end # module Methods end # class Equalizer ruby-equalizer-0.0.9/lib/equalizer/000077500000000000000000000000001225724242300172525ustar00rootroot00000000000000ruby-equalizer-0.0.9/lib/equalizer/version.rb000066400000000000000000000001571225724242300212670ustar00rootroot00000000000000# encoding: utf-8 class Equalizer < Module # Gem version VERSION = '0.0.9'.freeze end # class Equalizer ruby-equalizer-0.0.9/metadata.yml000066400000000000000000000042311225724242300170060ustar00rootroot00000000000000--- !ruby/object:Gem::Specification name: equalizer version: !ruby/object:Gem::Version version: 0.0.9 platform: ruby authors: - Dan Kubb - Markus Schirp autorequire: bindir: bin cert_chain: [] date: 2013-12-23 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: bundler requirement: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '1.3' - - '>=' - !ruby/object:Gem::Version version: 1.3.5 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '1.3' - - '>=' - !ruby/object:Gem::Version version: 1.3.5 description: Module to define equality, equivalence and inspection methods email: - dan.kubb@gmail.com - mbj@schirp-dso.com executables: [] extensions: [] extra_rdoc_files: - LICENSE - README.md - CONTRIBUTING.md files: - .gitignore - .reek.yml - .rspec - .rubocop.yml - .ruby-gemset - .travis.yml - .yardstick.yml - CONTRIBUTING.md - Gemfile - LICENSE - README.md - Rakefile - equalizer.gemspec - lib/equalizer.rb - lib/equalizer/version.rb - spec/spec_helper.rb - spec/support/config_alias.rb - spec/unit/equalizer/included_spec.rb - spec/unit/equalizer/methods/eql_predicate_spec.rb - spec/unit/equalizer/methods/equality_operator_spec.rb - spec/unit/equalizer/universal_spec.rb homepage: https://github.com/dkubb/equalizer licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.1.11 signing_key: specification_version: 4 summary: Module to define equality, equivalence and inspection methods test_files: - spec/unit/equalizer/included_spec.rb - spec/unit/equalizer/methods/eql_predicate_spec.rb - spec/unit/equalizer/methods/equality_operator_spec.rb - spec/unit/equalizer/universal_spec.rb ruby-equalizer-0.0.9/spec/000077500000000000000000000000001225724242300154355ustar00rootroot00000000000000ruby-equalizer-0.0.9/spec/spec_helper.rb000066400000000000000000000011741225724242300202560ustar00rootroot00000000000000# encoding: utf-8 if ENV['COVERAGE'] == 'true' require 'simplecov' require 'coveralls' SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter, ] SimpleCov.start do command_name 'spec:unit' add_filter 'config' add_filter 'spec' add_filter 'vendor' minimum_coverage 100 end end require 'equalizer' # TODO: FIXME! # Cache correct freezer in ice_nine before # rspec2 infects the world... Equalizer.new RSpec.configure do |config| config.expect_with :rspec do |expect_with| expect_with.syntax = :expect end end ruby-equalizer-0.0.9/spec/support/000077500000000000000000000000001225724242300171515ustar00rootroot00000000000000ruby-equalizer-0.0.9/spec/support/config_alias.rb000066400000000000000000000001251225724242300221120ustar00rootroot00000000000000# encoding: utf-8 require 'rbconfig' ::Config = RbConfig unless defined?(::Config) ruby-equalizer-0.0.9/spec/unit/000077500000000000000000000000001225724242300164145ustar00rootroot00000000000000ruby-equalizer-0.0.9/spec/unit/equalizer/000077500000000000000000000000001225724242300204155ustar00rootroot00000000000000ruby-equalizer-0.0.9/spec/unit/equalizer/included_spec.rb000066400000000000000000000023531225724242300235460ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Equalizer, '#included' do subject { descendant.instance_exec(object) { |mod| include mod } } let(:object) { described_class.new } let(:descendant) { Class.new } let(:superclass) { described_class.superclass } before do # Prevent Module.included from being called through inheritance described_class::Methods.stub(:included) end around do |example| # Restore included method after each example superclass.class_eval do alias_method :original_included, :included example.call undef_method :included alias_method :included, :original_included end end it 'delegates to the superclass #included method' do # This is the most succinct approach I could think of to test whether the # superclass#included method is called. All of the built-in rspec helpers # did not seem to work for this. included = false superclass.class_eval { define_method(:included) { |_| included = true } } expect { subject }.to change { included }.from(false).to(true) end it 'includes methods into the descendant' do subject expect(descendant.included_modules).to include(described_class::Methods) end end ruby-equalizer-0.0.9/spec/unit/equalizer/methods/000077500000000000000000000000001225724242300220605ustar00rootroot00000000000000ruby-equalizer-0.0.9/spec/unit/equalizer/methods/eql_predicate_spec.rb000066400000000000000000000022651225724242300262250ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Equalizer::Methods, '#eql?' do subject { object.eql?(other) } let(:object) { described_class.new(true) } let(:described_class) do Class.new do include Equalizer::Methods attr_reader :boolean def initialize(boolean) @boolean = boolean end def cmp?(comparator, other) boolean.send(comparator, other.boolean) end end end context 'with the same object' do let(:other) { object } it { should be(true) } it 'is symmetric' do should eql(other.eql?(object)) end end context 'with an equivalent object' do let(:other) { object.dup } it { should be(true) } it 'is symmetric' do should eql(other.eql?(object)) end end context 'with an equivalent object of a subclass' do let(:other) { Class.new(described_class).new(true) } it { should be(false) } it 'is symmetric' do should eql(other.eql?(object)) end end context 'with a different object' do let(:other) { described_class.new(false) } it { should be(false) } it 'is symmetric' do should eql(other.eql?(object)) end end end ruby-equalizer-0.0.9/spec/unit/equalizer/methods/equality_operator_spec.rb000066400000000000000000000042601225724242300271710ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Equalizer::Methods, '#==' do subject { object == other } let(:object) { described_class.new(true) } let(:described_class) { Class.new(super_class) } let(:super_class) do Class.new do include Equalizer::Methods attr_reader :boolean def initialize(boolean) @boolean = boolean end def cmp?(comparator, other) boolean.send(comparator, other.boolean) end end end context 'with the same object' do let(:other) { object } it { should be(true) } it 'is symmetric' do should eql(other == object) end end context 'with an equivalent object' do let(:other) { object.dup } it { should be(true) } it 'is symmetric' do should eql(other == object) end end context 'with a subclass instance having equivalent obervable state' do let(:other) { Class.new(described_class).new(true) } it { should be(true) } it 'is not symmetric' do # the subclass instance should maintain substitutability with the object # (in the LSP sense) the reverse is not true. should_not eql(other == object) end end context 'with a superclass instance having equivalent observable state' do let(:other) { super_class.new(true) } it { should be(false) } it 'is not symmetric' do should_not eql(other == object) end end context 'with an object of another class' do let(:other) { Class.new.new } it { should be(false) } it 'is symmetric' do should eql(other == object) end end context 'with an equivalent object after coercion' do let(:other) { Object.new } before do # declare a private #coerce method described_class.class_eval do def coerce(other) self.class.new(!!other) end private :coerce end end it { should be(true) } it 'is not symmetric' do should_not eql(other == object) end end context 'with a different object' do let(:other) { described_class.new(false) } it { should be(false) } it 'is symmetric' do should eql(other == object) end end end ruby-equalizer-0.0.9/spec/unit/equalizer/universal_spec.rb000066400000000000000000000075161225724242300237750ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Equalizer, '.new' do let(:object) { described_class } let(:name) { 'User' } let(:klass) { ::Class.new } context 'with no keys' do subject { object.new } before do # specify the class #name method klass.stub(:name).and_return(name) klass.send(:include, subject) end let(:instance) { klass.new } it { should be_instance_of(object) } it { should be_frozen } it 'defines #hash and #inspect methods dynamically' do expect(subject.public_instance_methods(false).map(&:to_s).sort). to eql(%w[hash inspect]) end describe '#eql?' do context 'when the objects are similar' do let(:other) { instance.dup } it { expect(instance.eql?(other)).to be(true) } end context 'when the objects are different' do let(:other) { double('other') } it { expect(instance.eql?(other)).to be(false) } end end describe '#==' do context 'when the objects are similar' do let(:other) { instance.dup } it { expect(instance == other).to be(true) } end context 'when the objects are different' do let(:other) { double('other') } it { expect(instance == other).to be(false) } end end describe '#hash' do it 'has the expected arity' do expect(klass.instance_method(:hash).arity).to be(0) end it { expect(instance.hash).to eql([klass].hash) } end describe '#inspect' do it 'has the expected arity' do expect(klass.instance_method(:inspect).arity).to be(0) end it { expect(instance.inspect).to eql('#') } end end context 'with keys' do subject { object.new(*keys) } let(:keys) { [:firstname, :lastname].freeze } let(:firstname) { 'John' } let(:lastname) { 'Doe' } let(:instance) { klass.new(firstname, lastname) } let(:klass) do ::Class.new do attr_reader :firstname, :lastname private :firstname, :lastname def initialize(firstname, lastname) @firstname, @lastname = firstname, lastname end end end before do # specify the class #inspect method klass.stub(:name).and_return(nil) klass.stub(:inspect).and_return(name) klass.send(:include, subject) end it { should be_instance_of(object) } it { should be_frozen } it 'defines #hash and #inspect methods dynamically' do expect(subject.public_instance_methods(false).map(&:to_s).sort). to eql(%w[ hash inspect ]) end describe '#eql?' do context 'when the objects are similar' do let(:other) { instance.dup } it { expect(instance.eql?(other)).to be(true) } end context 'when the objects are different' do let(:other) { double('other') } it { expect(instance.eql?(other)).to be(false) } end end describe '#==' do context 'when the objects are similar' do let(:other) { instance.dup } it { expect(instance == other).to be(true) } end context 'when the objects are different type' do let(:other) { klass.new('Foo', 'Bar') } it { expect(instance == other).to be(false) } end context 'when the objects are from different type' do let(:other) { double('other') } it { expect(instance == other).to be(false) } end end describe '#hash' do it 'returns the expected hash' do expect(instance.hash). to eql([firstname, lastname, klass].hash) end end describe '#inspect' do it 'returns the expected string' do expect(instance.inspect). to eql('#') end end end end