browsing_history 0.0.2
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 +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.rubocop.yml +89 -0
- data/.rubocop_todo.yml +28 -0
- data/.ruby-version +1 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +180 -0
- data/LICENSE +21 -0
- data/MIT-LICENSE +20 -0
- data/README.md +2 -0
- data/README.rdoc +3 -0
- data/Rakefile +28 -0
- data/browsing_history.gemspec +34 -0
- data/dump.rdb +1 -0
- data/lib/browsing_history/browser.rb +66 -0
- data/lib/browsing_history/configuration.rb +38 -0
- data/lib/browsing_history/error.rb +2 -0
- data/lib/browsing_history/historizable.rb +26 -0
- data/lib/browsing_history/history.rb +85 -0
- data/lib/browsing_history/storage.rb +44 -0
- data/lib/browsing_history/storages/active_record.rb +12 -0
- data/lib/browsing_history/storages/base.rb +40 -0
- data/lib/browsing_history/storages/redis.rb +113 -0
- data/lib/browsing_history/version.rb +3 -0
- data/lib/browsing_history.rb +12 -0
- data/lib/generators/active_record/migration_generator.rb +12 -0
- data/lib/generators/active_record/templates/migration.rb +15 -0
- data/lib/tasks/browsing_history_tasks.rake +4 -0
- data/spec/browsing_history/browser_spec.rb +156 -0
- data/spec/browsing_history/configration_spec.rb +16 -0
- data/spec/browsing_history/fixtures/article.rb +10 -0
- data/spec/browsing_history/fixtures/user.rb +10 -0
- data/spec/browsing_history/historizable_spec.rb +27 -0
- data/spec/browsing_history/history_spec.rb +273 -0
- data/spec/browsing_history/storage_spec.rb +45 -0
- data/spec/browsing_history/storages/base_spec.rb +35 -0
- data/spec/browsing_history/storages/redis_spec.rb +141 -0
- data/spec/browsing_history_spec.rb +4 -0
- data/spec/generator_spec.rb +34 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/test_app/README.rdoc +28 -0
- data/spec/test_app/Rakefile +6 -0
- data/spec/test_app/app/assets/images/.keep +0 -0
- data/spec/test_app/app/assets/javascripts/application.js +13 -0
- data/spec/test_app/app/assets/stylesheets/application.css +15 -0
- data/spec/test_app/app/controllers/application_controller.rb +10 -0
- data/spec/test_app/app/controllers/articles_controller.rb +17 -0
- data/spec/test_app/app/controllers/concerns/.keep +0 -0
- data/spec/test_app/app/helpers/application_helper.rb +2 -0
- data/spec/test_app/app/mailers/.keep +0 -0
- data/spec/test_app/app/models/.keep +0 -0
- data/spec/test_app/app/models/concerns/.keep +0 -0
- data/spec/test_app/app/views/layouts/application.html.erb +14 -0
- data/spec/test_app/bin/bundle +3 -0
- data/spec/test_app/bin/rails +4 -0
- data/spec/test_app/bin/rake +4 -0
- data/spec/test_app/bin/setup +29 -0
- data/spec/test_app/config/application.rb +19 -0
- data/spec/test_app/config/boot.rb +5 -0
- data/spec/test_app/config/database.yml +12 -0
- data/spec/test_app/config/environment.rb +5 -0
- data/spec/test_app/config/environments/development.rb +18 -0
- data/spec/test_app/config/environments/test.rb +21 -0
- data/spec/test_app/config/initializers/assets.rb +11 -0
- data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/test_app/config/initializers/cookies_serializer.rb +3 -0
- data/spec/test_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/test_app/config/initializers/inflections.rb +16 -0
- data/spec/test_app/config/initializers/mime_types.rb +4 -0
- data/spec/test_app/config/initializers/session_store.rb +3 -0
- data/spec/test_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/test_app/config/locales/en.yml +23 -0
- data/spec/test_app/config/routes.rb +2 -0
- data/spec/test_app/config/secrets.yml +5 -0
- data/spec/test_app/config.ru +4 -0
- data/spec/test_app/db/development.sqlite3 +0 -0
- data/spec/test_app/db/test.sqlite3 +0 -0
- data/spec/test_app/lib/assets/.keep +0 -0
- data/spec/test_app/log/.keep +0 -0
- data/spec/test_app/log/development.log +0 -0
- data/spec/test_app/log/test.log +0 -0
- data/spec/test_app/public/404.html +67 -0
- data/spec/test_app/public/422.html +67 -0
- data/spec/test_app/public/500.html +66 -0
- data/spec/test_app/public/favicon.ico +0 -0
- metadata +342 -0
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            require 'browsing_history/storages/base'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module BrowsingHistory::Storage
         | 
| 4 | 
            +
              class InvalidStorage < BrowsingHistory::Error; end
         | 
| 5 | 
            +
              class StoragesNotSet < BrowsingHistory::Error; end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              def self.included(klass)
         | 
| 8 | 
            +
                klass.extend ConfigureMethods
         | 
| 9 | 
            +
                klass.init_storages
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              module ConfigureMethods
         | 
| 13 | 
            +
                attr_reader :current_storage_type
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def current_storage
         | 
| 16 | 
            +
                  storages[current_storage_type]
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def storages
         | 
| 20 | 
            +
                  @storages ||= {}
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def attach_storage(storage_type, **opts)
         | 
| 24 | 
            +
                  storage = storages[storage_type]
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  if storage
         | 
| 27 | 
            +
                    storage.connect(opts)
         | 
| 28 | 
            +
                    @current_storage_type = storage_type
         | 
| 29 | 
            +
                  else
         | 
| 30 | 
            +
                    raise InvalidStorage
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def init_storages
         | 
| 35 | 
            +
                  BrowsingHistory.storage_types.each do |key|
         | 
| 36 | 
            +
                    storages[key] =
         | 
| 37 | 
            +
                      "BrowsingHistory::Storages::#{key.to_s.camelize}".constantize
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  raise StoragesNotSet if storages.empty?
         | 
| 41 | 
            +
                  attach_storage(storages.keys.first)
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            module BrowsingHistory::Storages
         | 
| 2 | 
            +
              IOMethods = %i(fetch add update clear count interface).freeze
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              class NotOverideError < BrowsingHistory::Error; end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              class Base
         | 
| 7 | 
            +
                attr_accessor :browser, :historizable, :options
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def initialize(browser, historizable)
         | 
| 10 | 
            +
                  @browser      = browser
         | 
| 11 | 
            +
                  @historizable = historizable
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def method_missing(method, *args)
         | 
| 15 | 
            +
                  if method.in?(IOMethods)
         | 
| 16 | 
            +
                    raise NotOverideError
         | 
| 17 | 
            +
                  else
         | 
| 18 | 
            +
                    super
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                class << self
         | 
| 23 | 
            +
                  def connect
         | 
| 24 | 
            +
                    IOMethods.each do |method|
         | 
| 25 | 
            +
                      define_singleton_method(method) do |browser, historizable, *_args|
         | 
| 26 | 
            +
                        opts = _args.dup.extract_options!.merge(default_options)
         | 
| 27 | 
            +
                        new(browser, historizable).send(method, **opts)
         | 
| 28 | 
            +
                      end
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def default_options
         | 
| 33 | 
            +
                    {}
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              require 'browsing_history/storages/redis'
         | 
| 39 | 
            +
              require 'browsing_history/storages/active_record'
         | 
| 40 | 
            +
            end
         | 
| @@ -0,0 +1,113 @@ | |
| 1 | 
            +
            require 'redis'
         | 
| 2 | 
            +
            require 'redis-objects'
         | 
| 3 | 
            +
            require 'redis-namespace'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class BrowsingHistory::Storages::Redis < BrowsingHistory::Storages::Base
         | 
| 6 | 
            +
              def fetch(opts)
         | 
| 7 | 
            +
                if opts[:between]
         | 
| 8 | 
            +
                  fetch_between(**opts)
         | 
| 9 | 
            +
                elsif opts[:at]
         | 
| 10 | 
            +
                  history.at(opts[:at])
         | 
| 11 | 
            +
                else
         | 
| 12 | 
            +
                  limit = opts[:limit].try(:-, 1) || opts.delete(:end)
         | 
| 13 | 
            +
                  history.revrange(opts.delete(:start), limit, **opts)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def add(_opts)
         | 
| 18 | 
            +
                history.add(historizable, score)
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              def update(opts)
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              def clear(opts)
         | 
| 25 | 
            +
                if opts[:expiration]
         | 
| 26 | 
            +
                  clear_expiration(opts)
         | 
| 27 | 
            +
                elsif opts[:all]
         | 
| 28 | 
            +
                  clear_all
         | 
| 29 | 
            +
                else
         | 
| 30 | 
            +
                  history.delete(historizable)
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def count(opts)
         | 
| 35 | 
            +
                if opts[:between]
         | 
| 36 | 
            +
                  count_between(opts)
         | 
| 37 | 
            +
                else
         | 
| 38 | 
            +
                  history.range_size(
         | 
| 39 | 
            +
                    history.score(history.first),
         | 
| 40 | 
            +
                    history.score(history.last)
         | 
| 41 | 
            +
                  )
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              def interface(_opts)
         | 
| 46 | 
            +
                history
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              private
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              def history
         | 
| 52 | 
            +
                key = %(\
         | 
| 53 | 
            +
                  #{browser.browser_type}/\
         | 
| 54 | 
            +
                  #{browser.browser_id}/\
         | 
| 55 | 
            +
                  #{historizable.historizable_type}\
         | 
| 56 | 
            +
                ).delete(' ')
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                self.class.set.new(key, marshal: true)
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              def fetch_between(opts)
         | 
| 62 | 
            +
                start_date, end_date = parse_between(opts.delete(:between))
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                history.revrangebyscore(start_date, end_date, **opts)
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              def clear_expiration(opts)
         | 
| 68 | 
            +
                min_score = history.score(history.first)
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                history.remrangebyscore(min_score, score(opts[:expiration]))
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              def clear_all
         | 
| 74 | 
            +
                history.remrangebyrank(0, -1)
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
              def count_between(opts)
         | 
| 78 | 
            +
                end_date, start_date = parse_between(opts.delete(:between))
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                history.range_size(start_date, end_date)
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              def score(time = nil)
         | 
| 84 | 
            +
                time ? time.to_f : Time.now.to_f
         | 
| 85 | 
            +
              end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
              def parse_between(range)
         | 
| 88 | 
            +
                [range.first.to_f, range.last.to_f]
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
              class << self
         | 
| 92 | 
            +
                attr_reader :redis, :set
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                def connect(opts = {})
         | 
| 95 | 
            +
                  @redis = Redis::Namespace.new(
         | 
| 96 | 
            +
                    BrowsingHistory.namespace,
         | 
| 97 | 
            +
                    redis: Redis.new(default_connect_options.merge(opts))
         | 
| 98 | 
            +
                  )
         | 
| 99 | 
            +
                  Redis::Objects.redis = @redis
         | 
| 100 | 
            +
                  @set = Redis::SortedSet
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  super()
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                def default_options
         | 
| 106 | 
            +
                  { start: 0, end: -1 }
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                def default_connect_options
         | 
| 110 | 
            +
                  { host:  '127.0.0.1', port: 6379, db: 0 }
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
              end
         | 
| 113 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            require 'active_support'
         | 
| 2 | 
            +
            require 'active_support/core_ext'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module BrowsingHistory
         | 
| 5 | 
            +
              require 'browsing_history/error'
         | 
| 6 | 
            +
              require 'browsing_history/configuration'
         | 
| 7 | 
            +
              extend Configuration
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              require 'browsing_history/history'
         | 
| 10 | 
            +
              require 'browsing_history/browser'
         | 
| 11 | 
            +
              require 'browsing_history/historizable'
         | 
| 12 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            require 'rails/generators'
         | 
| 2 | 
            +
            require 'rails/generators/actions'
         | 
| 3 | 
            +
            require 'rails/generators/active_record'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class BrowsingHistory::MigrationGenerator < ActiveRecord::Generators::Base
         | 
| 6 | 
            +
              source_root File.expand_path('templates', __dir__)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              argument :name, type: :string, default: 'browsing_histories'
         | 
| 9 | 
            +
              def generate_files
         | 
| 10 | 
            +
                migration_template 'migration.rb', "db/migrate/create_#{name}.rb"
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            class CreateBrowsingHistories < ActiveRecord::Migration
         | 
| 2 | 
            +
              # Create table
         | 
| 3 | 
            +
              def up
         | 
| 4 | 
            +
                create_table :browsing_histories do |t|
         | 
| 5 | 
            +
                  t.references :browser,      polymorphic: true, index: true
         | 
| 6 | 
            +
                  t.references :historizable, polymorphic: true, index: true
         | 
| 7 | 
            +
                  t.text       :object,       null: false
         | 
| 8 | 
            +
                  t.timestamps                null: false
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              # Drop table
         | 
| 13 | 
            +
              def down
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,156 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'fixtures/user'
         | 
| 3 | 
            +
            require 'fixtures/article'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe BrowsingHistory::Browser do
         | 
| 6 | 
            +
              articles_size = 50
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              let(:user)    { User.new }
         | 
| 9 | 
            +
              let(:article) { Article.new }
         | 
| 10 | 
            +
              let(:articles) do
         | 
| 11 | 
            +
                articles_size.times.map.with_index(1) { |i| Article.new(i) }
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
              let(:histories) { user.browsing_histories }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              describe 'respond_to' do
         | 
| 16 | 
            +
                context 'instance' do
         | 
| 17 | 
            +
                  subject { user }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  it { is_expected.to respond_to(:browsing_histories) }
         | 
| 20 | 
            +
                  it { is_expected.to respond_to(:browser_id) }
         | 
| 21 | 
            +
                  it { is_expected.to respond_to(:browser_type) }
         | 
| 22 | 
            +
                  it { is_expected.to respond_to(:browser_class) }
         | 
| 23 | 
            +
                  it { is_expected.to respond_to(:browser_instance?) }
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                context 'singleton' do
         | 
| 27 | 
            +
                  subject { user.class }
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  it { is_expected.to respond_to(:browser_id) }
         | 
| 30 | 
            +
                  it { is_expected.to respond_to(:browser_type) }
         | 
| 31 | 
            +
                  it { is_expected.to respond_to(:browser_class) }
         | 
| 32 | 
            +
                  it { is_expected.to respond_to(:browser_instance?) }
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              describe 'assosiation' do
         | 
| 37 | 
            +
                describe 'respond_to' do
         | 
| 38 | 
            +
                  subject { user.browsing_histories }
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  it { is_expected.to respond_to(:recent) }
         | 
| 41 | 
            +
                  it { is_expected.to respond_to(:previous) }
         | 
| 42 | 
            +
                  it { is_expected.to respond_to(:add) }
         | 
| 43 | 
            +
                  it { is_expected.to respond_to(:<<) }
         | 
| 44 | 
            +
                  it { is_expected.to respond_to(:count) }
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                describe '#initialize' do
         | 
| 48 | 
            +
                  subject { user.browsing_histories }
         | 
| 49 | 
            +
                  it { is_expected.to be_a("#{described_class}::Association".constantize) }
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                describe '#recent' do
         | 
| 53 | 
            +
                  context 'default' do
         | 
| 54 | 
            +
                    it 'should default empty' do
         | 
| 55 | 
            +
                      expect(histories.recent(article)).to be_empty
         | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  context 'when histories exist' do
         | 
| 60 | 
            +
                    before(:each) do
         | 
| 61 | 
            +
                      articles.each { |article| histories << article }
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                    let(:recent_articles) { histories.recent(article, limit: articles.size) }
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    it 'should equal original' do
         | 
| 66 | 
            +
                      recent_articles.each_with_index do |article, i|
         | 
| 67 | 
            +
                        original = articles.reverse[i]
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                        expect(article.id).to eq(original.id)
         | 
| 70 | 
            +
                        expect(article.title).to eq(original.title)
         | 
| 71 | 
            +
                      end
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                describe '#previous' do
         | 
| 77 | 
            +
                  context 'default' do
         | 
| 78 | 
            +
                    it 'should default empty' do
         | 
| 79 | 
            +
                      expect(histories.previous(article, Time.now..1.day.ago)).to be_empty
         | 
| 80 | 
            +
                    end
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  context 'when histories exist' do
         | 
| 84 | 
            +
                    before do
         | 
| 85 | 
            +
                      articles.each { |article| histories << article }
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    let(:recent_article) { Article.new(100) }
         | 
| 89 | 
            +
                    let(:previous_article) do
         | 
| 90 | 
            +
                      histories.previous(article, Time.now..5.seconds.ago)
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                    it 'should return 1 historizable' do
         | 
| 94 | 
            +
                      sleep(6)
         | 
| 95 | 
            +
                      histories << recent_article
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                      expect(previous_article.size).to eq(1)
         | 
| 98 | 
            +
                      expect(previous_article.first.id).to eq(recent_article.id)
         | 
| 99 | 
            +
                      expect(previous_article.first.title).to eq(recent_article.title)
         | 
| 100 | 
            +
                    end
         | 
| 101 | 
            +
                  end
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                describe '#add' do
         | 
| 105 | 
            +
                  context 'add' do
         | 
| 106 | 
            +
                    it 'should return historizable' do
         | 
| 107 | 
            +
                      expect(histories.add(article)).to be_truthy
         | 
| 108 | 
            +
                    end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                    context 'before add historizable' do
         | 
| 111 | 
            +
                      before { histories.add(article) }
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                      let(:saved_article) { histories.recent(article).first }
         | 
| 114 | 
            +
                      it 'should equal original' do
         | 
| 115 | 
            +
                        expect(saved_article.id).to eq(article.id)
         | 
| 116 | 
            +
                        expect(saved_article.title).to eq(article.title)
         | 
| 117 | 
            +
                      end
         | 
| 118 | 
            +
                    end
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  context '<<' do
         | 
| 122 | 
            +
                    it 'should return historizable' do
         | 
| 123 | 
            +
                      expect(histories << article).to be_truthy
         | 
| 124 | 
            +
                    end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                    context 'before << historizable' do
         | 
| 127 | 
            +
                      before { histories << article }
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                      let(:saved_article) { histories.recent(article).first }
         | 
| 130 | 
            +
                      it 'should equal original' do
         | 
| 131 | 
            +
                        expect(saved_article.id).to eq(article.id)
         | 
| 132 | 
            +
                        expect(saved_article.title).to eq(article.title)
         | 
| 133 | 
            +
                      end
         | 
| 134 | 
            +
                    end
         | 
| 135 | 
            +
                  end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                  describe '#count' do
         | 
| 138 | 
            +
                    context 'default' do
         | 
| 139 | 
            +
                      it 'should default empty' do
         | 
| 140 | 
            +
                        expect(histories.count(article)).to eq(0)
         | 
| 141 | 
            +
                      end
         | 
| 142 | 
            +
                    end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                    context 'when histories exist' do
         | 
| 145 | 
            +
                      before do
         | 
| 146 | 
            +
                        articles.each { |article| histories << article }
         | 
| 147 | 
            +
                      end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                      it 'should return historizables count' do
         | 
| 150 | 
            +
                        expect(histories.count(article)).to eq(articles.size)
         | 
| 151 | 
            +
                      end
         | 
| 152 | 
            +
                    end
         | 
| 153 | 
            +
                  end
         | 
| 154 | 
            +
                end
         | 
| 155 | 
            +
              end
         | 
| 156 | 
            +
            end
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe BrowsingHistory::Configuration do
         | 
| 4 | 
            +
              let(:storage_types) { %i(redis active_record) }
         | 
| 5 | 
            +
              let(:storage_type) { storage_types.first }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              describe '#configure' do
         | 
| 8 | 
            +
                it 'should have default attributes' do
         | 
| 9 | 
            +
                  BrowsingHistory.configure do |configuration|
         | 
| 10 | 
            +
                    expect(configuration.storage_types).to eql(storage_types)
         | 
| 11 | 
            +
                    expect(configuration.storage_type).to eql(storage_type)
         | 
| 12 | 
            +
                    expect(configuration.namespace).to eql('browsing_history')
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'fixtures/user'
         | 
| 3 | 
            +
            require 'fixtures/article'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe BrowsingHistory::Browser do
         | 
| 6 | 
            +
              let(:article) { Article.new }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              describe 'respond_to' do
         | 
| 9 | 
            +
                context 'instance' do
         | 
| 10 | 
            +
                  subject { article }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  it { is_expected.to respond_to(:historizable_id) }
         | 
| 13 | 
            +
                  it { is_expected.to respond_to(:historizable_type) }
         | 
| 14 | 
            +
                  it { is_expected.to respond_to(:historizable_class) }
         | 
| 15 | 
            +
                  it { is_expected.to respond_to(:historizable_instance?) }
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                context 'singleton' do
         | 
| 19 | 
            +
                  subject { article.class }
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  it { is_expected.to respond_to(:historizable_id) }
         | 
| 22 | 
            +
                  it { is_expected.to respond_to(:historizable_type) }
         | 
| 23 | 
            +
                  it { is_expected.to respond_to(:historizable_class) }
         | 
| 24 | 
            +
                  it { is_expected.to respond_to(:historizable_instance?) }
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         |