Full Code of pokonski/public_activity for AI

main d8200889330c cached
72 files
99.7 KB
26.7k tokens
217 symbols
1 requests
Download .txt
Repository: pokonski/public_activity
Branch: main
Commit: d8200889330c
Files: 72
Total size: 99.7 KB

Directory structure:
gitextract_a19chaa2/

├── .editorconfig
├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── .travis.yml
├── Appraisals
├── CHANGELOG.md
├── Gemfile
├── MIT-LICENSE
├── README.md
├── Rakefile
├── gemfiles/
│   ├── .bundle/
│   │   └── config
│   ├── rails_6.1.gemfile
│   ├── rails_7.0.gemfile
│   └── rails_7.1.gemfile
├── lib/
│   ├── generators/
│   │   ├── public_activity/
│   │   │   ├── migration/
│   │   │   │   ├── migration_generator.rb
│   │   │   │   └── templates/
│   │   │   │       └── migration.rb
│   │   │   └── migration_upgrade/
│   │   │       ├── migration_upgrade_generator.rb
│   │   │       └── templates/
│   │   │           └── upgrade.rb
│   │   └── public_activity.rb
│   ├── public_activity/
│   │   ├── actions/
│   │   │   ├── creation.rb
│   │   │   ├── destruction.rb
│   │   │   └── update.rb
│   │   ├── activity.rb
│   │   ├── common.rb
│   │   ├── config.rb
│   │   ├── models/
│   │   │   ├── activist.rb
│   │   │   ├── activity.rb
│   │   │   ├── adapter.rb
│   │   │   └── trackable.rb
│   │   ├── orm/
│   │   │   ├── active_record/
│   │   │   │   ├── activist.rb
│   │   │   │   ├── activity.rb
│   │   │   │   ├── adapter.rb
│   │   │   │   └── trackable.rb
│   │   │   ├── active_record.rb
│   │   │   ├── mongo_mapper/
│   │   │   │   ├── activist.rb
│   │   │   │   ├── activity.rb
│   │   │   │   ├── adapter.rb
│   │   │   │   └── trackable.rb
│   │   │   ├── mongo_mapper.rb
│   │   │   ├── mongoid/
│   │   │   │   ├── activist.rb
│   │   │   │   ├── activity.rb
│   │   │   │   ├── adapter.rb
│   │   │   │   └── trackable.rb
│   │   │   └── mongoid.rb
│   │   ├── renderable.rb
│   │   ├── roles/
│   │   │   ├── deactivatable.rb
│   │   │   └── tracked.rb
│   │   ├── testing.rb
│   │   ├── utility/
│   │   │   ├── store_controller.rb
│   │   │   └── view_helpers.rb
│   │   └── version.rb
│   └── public_activity.rb
├── public_activity.gemspec
├── public_activity.sublime-project
└── test/
    ├── migrations/
    │   ├── 002_create_articles.rb
    │   ├── 003_create_users.rb
    │   └── 004_add_nonstandard_to_activities.rb
    ├── mongo_mapper.yml
    ├── mongoid.yml
    ├── test_activist.rb
    ├── test_activity.rb
    ├── test_common.rb
    ├── test_controller_integration.rb
    ├── test_generators.rb
    ├── test_helper.rb
    ├── test_testing.rb
    ├── test_tracking.rb
    ├── test_view_helpers.rb
    └── views/
        ├── custom/
        │   ├── _layout.erb
        │   └── _test.erb
        ├── layouts/
        │   └── _activity.erb
        └── public_activity/
            └── _test.erb

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.{json,yml}]
indent_size = 2

[*.{diff,md}]
trim_trailing_whitespace = false


================================================
FILE: .github/workflows/main.yml
================================================
name: CI
on:
  pull_request:
    paths-ignore:
      - 'README.md'
  push:
    paths-ignore:
      - 'README.md'
  workflow_dispatch:
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        ruby_version: ['3.0', '3.1', '3.2', '3.3']
        rails_version: ['6.1', '7.0', '7.1']
        exclude:
          - ruby_version: 3.1
            rails_version: 6.1
          - ruby_version: 3.2
            rails_version: 6.1
          - ruby_version: 3.3
            rails_version: 6.1
    steps:
      - uses: actions/checkout@v4
      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: ${{ matrix.ruby_version }}
      - name: Build and run test
        run: |
          bundle
          bundle exec appraisal rails_${{ matrix.rails_version }} bundle
          bundle exec appraisal rails_${{ matrix.rails_version }} rake


================================================
FILE: .gitignore
================================================
/doc/
/.yardoc/
*.gem
/coverage/
/*.sublime-workspace
/tmp
/Gemfile.lock
/gemfiles/*.lock

================================================
FILE: .travis.yml
================================================
language: ruby
rvm:
  - 2.2.6
  - 2.3.3
matrix:
  include:
    - rvm: 2.2.6
      gemfile: gemfiles/Gemfile.rails-4.0
      env: PA_ORM=active_record
    - rvm: 2.3.3
      gemfile: gemfiles/Gemfile.rails-4.0
      env: PA_ORM=active_record
    - rvm: 2.3.3
      gemfile: gemfiles/Gemfile.rails-5.0
      env: PA_ORM=active_record
    - rvm: 2.5.1
      gemfile: gemfiles/Gemfile.rails-5.2
      env: PA_ORM=active_record
    - rvm: 2.2.6
      env: PA_ORM=mongoid
env:
  - PA_ORM=active_record
  - PA_ORM=mongo_mapper
services:
  - mongodb
email:
  recipients:
    - piotrek@okonski.org
  on_success: change
  on_failure: always


================================================
FILE: Appraisals
================================================
# frozen_string_literal: true

if RUBY_VERSION.to_f < 3.1
  appraise 'rails_6.1' do
    gem 'rails', '~> 6.1.0'
    gem 'openssl'
  end
end

appraise 'rails_7.0' do
  gem 'rails', '~> 7.0.1'
end

appraise 'rails_7.1' do
  gem 'rails', '~> 7.1.0'
end


================================================
FILE: CHANGELOG.md
================================================
# Changelog

## 3.0.2

- **Fixed** Refactor prepare_parameters method to handle nil parameters (s. #387, thanks [Himalaya Pal](https://github.com/palhimalaya))
- **Fixed** CI failure due to lax sqlite3 version constraint (s. #389, thanks [Junichi Sato](https://github.com/sato11))

## 3.0.1

- **Fixed** Rails 6.1/7.0 regression in serialization of `nil`/`NULL` values
- **Fixed** Docs for `ORM::ActiveRecord::Activist`

## 3.0.0

- **Added** Rails 7.1 support (s. #384, thanks [max.jos](https://github.com/yhru))
- **Removed** Ruby <= 2.7 support
- **Removed** Rails <= 6.0 support

## 2.0.2

- **Fixed** Rescue from `ActiveRecord::ConnectionNotEstablished` (s. #372, thanks [Gabe Blair](https://github.com/gblair) & [Vitalie Lazu](https://github.com/vitaliel))

## 2.0.1

- **Fixed** Fix regression in generated migration (s. #368, thanks [Colin Bonner](https://github.com/cfbonner))

## 2.0.0

- **Fixed** Deprecation warnings in Ruby 2.7/3.0 due to double splat operator
- **Fixed** Ruby warnings due to unused variables `e` in exception handling
- **Added** Ruby 3.1 support
- **Added** Rails 7.0 support
- **Removed** Ruby <= 2.4 support
- **Removed** Rails <= 4.2 support

## 1.6.4

- **Fixed** exception when not using MySQL or Postgres (see #335, thanks to [Roland Netzsch](https://github.com/stuxcrystal))
- **Added** `create_activity!` method which raises exception on failures, much like `save!` in ActiveRecord (see #334, thanks to [Jonathan](https://github.com/jtwhittington))
- **Added** support for ActiveRecord 6 by whitelisting it (see #332, thanks to [Emre Demir](https://github.com/demir))
- **Added** frozen_string_literal pragma to Ruby files for better performance (see #329, thanks to [Krzysztof Rybka](https://github.com/krzysiek1507))

## 1.6.3

- **Fixed** a bug which resulted in crashes when PostgreSQL connection failed (see #328, thanks to [Ken Greeff](https://github.com/kengreeff))
- **Fixed** a bug which resulted in crashes when MySQL connection failed (see #327, thanks to [Miquel Sabaté Solà](https://github.com/mssola))

## 1.6.2

- **Fixed** a bug which resulted in crashes when database didn't exist (see #323, thanks to [Anmol Chopra](https://github.com/chopraanmol1))

## 1.6.1

- **Fixed** a bug with requiring not existent file in generated migrations

## 1.6.0

* **Add support for Rails 5.2**
* Make config settings thread safe (fixes #284)
* Fix Rspec tests failing in Rails 5 due to ViewHelpers (see #271, thanks to [Janusz](https://github.com/januszm))
* Support JSON, JSONB and HSTORE types for `parameters` column (see #285, thanks to [djvs](https://github.com/djvs) and #315 (thanks to [mateusg](https://github.com/mateusg))

## 1.5.0

* Refactor PublicActivity::StoreController to rely on Thread.current instead. (see #252, thanks to [Ryan McGeary](https://github.com/rmm5t))
* Remove support for Ruby 1.9.3 and Ruby 2.0.0 (thanks to [Ryan McGeary](https://github.com/rmm5t))

## 1.4.2

* Fix bug with migrations not having an extension in ActiveRecord >= 4.0.0

## 1.4.1

* Fixed issue with Rails 4 when using ProtectedAttributes gem (see #128)
* General code clean-ups.

## 1.4.0

* Added support for MongoMapper ORM (thanks to [Julio Olivera](https://github.com/julioolvr)) [PR](https://github.com/pokonski/public_activity/pull/101)
* Added support for stable **Rails 4.0** while keeping compatibility with Rails 3.X
* `render_activity` can now render collections of activities instead of just a single one. Also aliased as `render_activities`
* Fix issue in rendering multiple activities when options were incomplete for every subsequent activity after the first one
* `render_activity` now accetps `:locals` option. Works the same way as `:locals` for Rails `render` method.

## 1.1.0

* Fixed an issue when AR was loading despite choosing Mongoid in multi-ORM Rails applications (thanks to [Robert Ulejczyk](https://github.com/robuye))

## 1.0.3

* Fixed a bug which modified globals (thanks to [Weera Wu](https://github.com/wulab))

## 1.0.2

* Fixed undefined constant PublicActivity::Activity for Activist associations (thanks to [Стас Сушков](https://github.com/stas))

## 1.0.1

* #create_activity now correctly returns activity object.
* Fixed :owner not being set correctly when passed to #create_activity (thanks to [Drew Miller](https://github.com/mewdriller))

## 1.0 (released 10/02/2013)

* **Now supports Mongoid 3 and Active Record.**
* Added indexes for polymorphic column pairs to speed up queries in ActiveRecord
* `#create_activity` now returns the newly created Activity object
* Support for custom Activity attributes. Now if you need a custom relation for Activities you can
  create a migration which adds the desired column, whitelist the attribute, and then you can simply pass the value to #create_activity
* `#tracked` can now accept a single Symbol for its `:only` and `:except` options.
* It is now possible to include `PublicActivity::Common` in your models if you just want to use `#create_activity` method
  and skip the default CRUD tracking.
* `#render_activity` now accepts Symbols or Strings for :layout parameter.
  ### Example

  ```ruby
  # All look for app/views/layouts/_activity.erb
  render_activity @activity, :layout => "activity"
  render_activity @activity, :layout => "layouts/activity"
  render_activity @activity, :layout => :activity
  ```
## 0.5.4

* Fixed support for namespaced classes when transforming into view path.

  For example `MyNamespace::CamelCase` now correctly transforms to key: `my_namespace_camel_case.create`


================================================
FILE: Gemfile
================================================
# frozen_string_literal: true

source "https://rubygems.org"
gemspec


================================================
FILE: MIT-LICENSE
================================================
Copyright (c) 2011-2013 Piotrek Okoński

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.


================================================
FILE: README.md
================================================
# PublicActivity [![Code Climate](https://codeclimate.com/github/chaps-io/public_activity.svg)](https://codeclimate.com/github/chaps-io/public_activity) [![Gem Version](https://badge.fury.io/rb/public_activity.svg)](http://badge.fury.io/rb/public_activity)

`public_activity` provides easy activity tracking for your **ActiveRecord**, **Mongoid 3** and **MongoMapper** models
in Rails 6.1+. Simply put: it records what has been changed or created and gives you the ability to present those
recorded activities to users - similarly to how GitHub does it.

## Table of contents

- [Ruby/Rails version support](#ruby-rails-version-support)
- [Table of contents](#table-of-contents)
- [Example](#example)
  - [Online demo](#online-demo)
- [Screencast](#screencast)
- [Setup](#setup)
  - [Gem installation](#gem-installation)
  - [Database setup](#database-setup)
  - [Model configuration](#model-configuration)
    - [Custom activities](#custom-activities)
  - [Displaying activities](#displaying-activities)
    - [Layouts](#layouts)
    - [Locals](#locals)
    - [Activity views](#activity-views)
    - [I18n](#I18n)
- [Testing](#testing)
- [Documentation](#documentation)
- [Common examples](#common-examples)
- [Help](#help)
- [License](#license)

## Ruby/Rails version support

Version `~> 3.0`` supports Ruby 3.0+ and Rails 6.1+. For older Ruby versions
(≤2.7) and Rails 5.0+ you can use version `~> 2.0` until you can upgrade to
newer versions of Ruby + Rails.

Issues related to those unsupported versions of Ruby/Rails will be closed
without resolution and PRs will not be accepted.

## Example

Here is a simple example showing what this gem is about:

![Example usage](http://i.imgur.com/q0TVx.png)

### Demo app

The source code of the demo is hosted here: https://github.com/pokonski/activity_blog

## Screencast

Ryan Bates made a [great screencast](http://railscasts.com/episodes/406-public-activity) describing how to integrate Public Activity in your Rails Application.

## Setup

### Gem installation

You can install `public_activity` as you would any other gem:

    gem install public_activity

or in your Gemfile:

```ruby
gem 'public_activity'
```

### Database setup

By default _public_activity_ uses Active Record. If you want to use Mongoid or MongoMapper as your backend, create
an initializer file in your Rails application with the corresponding code inside:

For _Mongoid:_

```ruby
# config/initializers/public_activity.rb
PublicActivity::Config.set do
  orm :mongoid
end
```

For _MongoMapper:_

```ruby
# config/initializers/public_activity.rb
PublicActivity::Config.set do
  orm :mongo_mapper
end
```

**(ActiveRecord only)** Create migration for activities and migrate the database (in your Rails project):

    rails g public_activity:migration
    rake db:migrate

### Model configuration

Include `PublicActivity::Model` and add `tracked` to the model you want to keep track of:

For _ActiveRecord:_

```ruby
class Article < ActiveRecord::Base
  include PublicActivity::Model
  tracked
end
```

For _Mongoid:_

```ruby
class Article
  include Mongoid::Document
  include PublicActivity::Model
  tracked
end
```

For _MongoMapper:_

```ruby
class Article
  include MongoMapper::Document
  include PublicActivity::Model
  tracked
end
```

And now, by default create/update/destroy activities are recorded in activities table.
This is all you need to start recording activities for basic CRUD actions.

_Optional_: If you don't need `#tracked` but still want the comfort of `#create_activity`,
you can include only the lightweight `Common` module instead of `Model`.

#### Custom activities

You can trigger custom activities by setting all your required parameters and triggering `create_activity`
on the tracked model, like this:

```ruby
@article.create_activity key: 'article.commented_on', owner: current_user
```

See this entry http://rubydoc.info/gems/public_activity/PublicActivity/Common:create_activity for more details.

### Displaying activities

To display them you simply query the `PublicActivity::Activity` model:

```ruby
# notifications_controller.rb
def index
  @activities = PublicActivity::Activity.all
end
```

And in your views:

```erb
<%= render_activities(@activities) %>
```

*Note*: `render_activity` is a helper for use in view templates. `render_activity(activity)` can be written as `activity.render(self)` and it will have the same meaning.

*Note*: `render_activities` is an alias for `render_activity` and does the same.

#### Layouts

You can also pass options to both `activity#render` and `#render_activity` methods, which are passed deeper
to the internally used `render_partial` method.
A useful example would be to render activities wrapped in layout, which shares common elements of an activity,
like a timestamp, owner's avatar etc:

```erb
<%= render_activities(@activities, layout: :activity) %>
```

The activity will be wrapped with the `app/views/layouts/_activity.erb` layout, in the above example.

**Important**: please note that layouts for activities are also partials. Hence the `_` prefix.

#### Locals

Sometimes, it's desirable to pass additional local variables to partials. It can be done this way:

```erb
<%= render_activity(@activity, locals: {friends: current_user.friends}) %>
```

*Note*: Before 1.4.0, one could pass variables directly to the options hash for `#render_activity` and access it from activity parameters. This functionality is retained in 1.4.0 and later, but the `:locals` method is **preferred**, since it prevents bugs from shadowing variables from activity parameters in the database.

#### Activity views

`public_activity` looks for views in `app/views/public_activity`.

For example, if you have an activity with `:key` set to `"activity.user.changed_avatar"`, the gem will look for a partial in `app/views/public_activity/user/_changed_avatar.(erb|haml|slim|something_else)`.

*Hint*: the `"activity."` prefix in `:key` is completely optional and kept for backwards compatibility, you can skip it in new projects.

If a view file does not exist, then p_a falls back to the old behaviour and tries to translate the activity `:key` using `I18n#translate` method (see the section below).

#### I18n

Translations are used by the `#text` method, to which you can pass additional options in form of a hash. `#render` method uses translations when view templates have not been provided. You can render pure i18n strings by passing `{display: :i18n}` to `#render_activity` or `#render`.

Translations should be put in your locale `.yml` files. To render pure strings from I18n Example structure:

```yaml
activity:
  article:
    create: 'Article has been created'
    update: 'Someone has edited the article'
    destroy: 'Some user removed an article!'
```

This structure is valid for activities with keys `"activity.article.create"` or `"article.create"`. As mentioned before, `"activity."` part of the key is optional.

## Testing

For RSpec you can first disable `public_activity` and add the `test_helper` in `rails_helper.rb` with:

```ruby
#rails_helper.rb
require 'public_activity/testing'

PublicActivity.enabled = false
```

In your specs you can then blockwise decide whether to turn `public_activity` on
or off.

```ruby
# file_spec.rb
PublicActivity.with_tracking do
  # your test code goes here
end

PublicActivity.without_tracking do
  # your test code goes here
end
```

## Documentation

For more documentation go [here](http://rubydoc.info/gems/public_activity/index)

## Common examples

* [[How to] Set the Activity's owner to current_user by default](https://github.com/pokonski/public_activity/wiki/%5BHow-to%5D-Set-the-Activity's-owner-to-current_user-by-default)
* [[How to] Disable tracking for a class or globally](https://github.com/pokonski/public_activity/wiki/%5BHow-to%5D-Disable-tracking-for-a-class-or-globally)
* [[How to] Create custom activities](https://github.com/pokonski/public_activity/wiki/%5BHow-to%5D-Create-custom-activities)
* [[How to] Use custom fields on Activity](https://github.com/pokonski/public_activity/wiki/%5BHow-to%5D-Use-custom-fields-on-Activity)

## Help

If you need help with using public_activity please visit our discussion group and ask a question there:

https://groups.google.com/forum/?fromgroups#!forum/public-activity

Please do not ask general questions in the Github Issues.

## License
Copyright (c) 2011-2013 Piotrek Okoński, released under the MIT license


================================================
FILE: Rakefile
================================================
# frozen_string_literal: true

require 'bundler/gem_tasks'
require 'rake'
require 'yard'
require 'yard/rake/yardoc_task'
require 'rake/testtask'

task default: :test

desc 'Generate documentation for the public_activity plugin.'
YARD::Rake::YardocTask.new do |doc|
  doc.files = ['lib/**/*.rb']
end

Rake::TestTask.new do |t|
  t.libs << 'test'
  t.test_files = FileList['test/test*.rb']
end


================================================
FILE: gemfiles/.bundle/config
================================================
---
BUNDLE_RETRY: "1"


================================================
FILE: gemfiles/rails_6.1.gemfile
================================================
# This file was generated by Appraisal

source "https://rubygems.org"

gem "rails", "~> 6.1.0"
gem "openssl"

gemspec path: "../"


================================================
FILE: gemfiles/rails_7.0.gemfile
================================================
# This file was generated by Appraisal

source "https://rubygems.org"

gem "rails", "~> 7.0.1"

gemspec path: "../"


================================================
FILE: gemfiles/rails_7.1.gemfile
================================================
# This file was generated by Appraisal

source "https://rubygems.org"

gem "rails", "~> 7.1.0"

gemspec path: "../"


================================================
FILE: lib/generators/public_activity/migration/migration_generator.rb
================================================
# frozen_string_literal: true

require 'generators/public_activity'
require 'rails/generators/active_record'

module PublicActivity
  module Generators
    # Migration generator that creates migration file from template
    class MigrationGenerator < ActiveRecord::Generators::Base
      extend Base

      argument :name, :type => :string, :default => 'create_activities'
      # Create migration in project's folder
      def generate_files
        migration_template 'migration.rb', "db/migrate/#{name}.rb"
      end
    end
  end
end


================================================
FILE: lib/generators/public_activity/migration/templates/migration.rb
================================================
# frozen_string_literal: true

# Migration responsible for creating a table with activities
class CreateActivities < ActiveRecord::Migration[6.1]
  def self.up
    create_table :activities do |t|
      t.belongs_to :trackable, polymorphic: true
      t.belongs_to :owner, polymorphic: true
      t.string :key
      t.text :parameters
      t.belongs_to :recipient, polymorphic: true

      t.timestamps
    end
  end

  # Drop table
  def self.down
    drop_table :activities
  end
end


================================================
FILE: lib/generators/public_activity/migration_upgrade/migration_upgrade_generator.rb
================================================
# frozen_string_literal: true

require 'generators/public_activity'
require 'rails/generators/active_record'

module PublicActivity
  module Generators
    # Migration generator that creates migration file from template
    class MigrationUpgradeGenerator < ActiveRecord::Generators::Base
      extend Base

      argument :name, :type => :string, :default => 'upgrade_activities'
      # Create migration in project's folder
      def generate_files
        migration_template 'upgrade.rb', "db/migrate/#{name}.rb"
      end
    end
  end
end


================================================
FILE: lib/generators/public_activity/migration_upgrade/templates/upgrade.rb
================================================
# frozen_string_literal: true

# Migration responsible for creating a table with activities
class UpgradeActivities < ActiveRecord::Migration[5.0]
  # Create table
  def self.change
    change_table :activities do |t|
      t.belongs_to :recipient, :polymorphic => true
    end
  end
end


================================================
FILE: lib/generators/public_activity.rb
================================================
# frozen_string_literal: true

require 'rails/generators/named_base'

module PublicActivity
  # A generator module with Activity table schema.
  module Generators
    # A base module
    module Base
      # Get path for migration template
      def source_root
        @_public_activity_source_root ||= File.expand_path(File.join('../public_activity', generator_name, 'templates'), __FILE__)
      end
    end
  end
end


================================================
FILE: lib/public_activity/actions/creation.rb
================================================
# frozen_string_literal: true

module PublicActivity
  # Handles creation of Activities upon destruction and update of tracked model.
  module Creation
    extend ActiveSupport::Concern

    included do
      after_create :activity_on_create
    end

    private

    # Creates activity upon creation of the tracked model
    def activity_on_create
      create_activity(:create)
    end
  end
end


================================================
FILE: lib/public_activity/actions/destruction.rb
================================================
# frozen_string_literal: true

module PublicActivity
  # Handles creation of Activities upon destruction of tracked model.
  module Destruction
    extend ActiveSupport::Concern

    included do
      before_destroy :activity_on_destroy
    end

    private

    # Records an activity upon destruction of the tracked model
    def activity_on_destroy
      create_activity(:destroy)
    end
  end
end


================================================
FILE: lib/public_activity/actions/update.rb
================================================
# frozen_string_literal: true

module PublicActivity
  # Handles creation of Activities upon destruction and update of tracked model.
  module Update
    extend ActiveSupport::Concern

    included do
      after_update :activity_on_update
    end

    private

    # Creates activity upon modification of the tracked model
    def activity_on_update
      # Either use #changed? method for Rails < 5.1 or #saved_changes? for recent versions
      create_activity(:update) if respond_to?(:saved_changes?) ? saved_changes? : changed?
    end
  end
end


================================================
FILE: lib/public_activity/activity.rb
================================================
# frozen_string_literal: true

module PublicActivity
  # Main model, stores all information about what happened,
  # who caused it, when and anything else.
  class Activity < inherit_orm("Activity")
  end
end


================================================
FILE: lib/public_activity/common.rb
================================================
# frozen_string_literal: true

module PublicActivity
  # Happens when creating custom activities without either action or a key.
  class NoKeyProvided < Exception; end

  # Used to smartly transform value from metadata to data.
  # Accepts Symbols, which it will send against context.
  # Accepts Procs, which it will execute with controller and context.
  # @since 0.4.0
  def self.resolve_value(context, thing)
    case thing
    when Symbol
      context.__send__(thing)
    when Proc
      thing.call(PublicActivity.get_controller, context)
    else
      thing
    end
  end

  # Common methods shared across the gem.
  module Common
    extend ActiveSupport::Concern

    included do
      include Trackable
      class_attribute :activity_owner_global, :activity_recipient_global,
                      :activity_params_global, :activity_hooks, :activity_custom_fields_global
      set_public_activity_class_defaults
    end

    # @!group Global options

    # @!attribute activity_owner_global
    #   Global version of activity owner
    #   @see #activity_owner
    #   @return [Model]

    # @!attribute activity_recipient_global
    #   Global version of activity recipient
    #   @see #activity_recipient
    #   @return [Model]

    # @!attribute activity_params_global
    #   Global version of activity parameters
    #   @see #activity_params
    #   @return [Hash<Symbol, Object>]

    # @!attribute activity_hooks
    #   @return [Hash<Symbol, Proc>]
    #   Hooks/functions that will be used to decide *if* the activity should get
    #   created.
    #
    #   The supported keys are:
    #   * :create
    #   * :update
    #   * :destroy

    # @!endgroup

    # @!group Instance options

    # Set or get parameters that will be passed to {Activity} when saving
    #
    # == Usage:
    #
    #   @article.activity_params = {:article_title => @article.title}
    #   @article.save
    #
    # This way you can pass strings that should remain constant, even when model attributes
    # change after creating this {Activity}.
    # @return [Hash<Symbol, Object>]
    attr_accessor :activity_params
    @activity_params = {}
    # Set or get owner object responsible for the {Activity}.
    #
    # == Usage:
    #
    #   # where current_user is an object of logged in user
    #   @article.activity_owner = current_user
    #   # OR: take @article.author association
    #   @article.activity_owner = :author
    #   # OR: provide a Proc with custom code
    #   @article.activity_owner = proc {|controller, model| model.author }
    #   @article.save
    #   @article.activities.last.owner #=> Returns owner object
    # @return [Model] Polymorphic model
    # @see #activity_owner_global
    attr_accessor :activity_owner
    @activity_owner = nil

    # Set or get recipient for activity.
    #
    # Association is polymorphic, thus allowing assignment of
    # all types of models. This can be used for example in the case of sending
    # private notifications for only a single user.
    # @return (see #activity_owner)
    attr_accessor :activity_recipient
    @activity_recipient = nil
    # Set or get custom i18n key passed to {Activity}, later used in {Renderable#text}
    #
    # == Usage:
    #
    #   @article = Article.new
    #   @article.activity_key = "my.custom.article.key"
    #   @article.save
    #   @article.activities.last.key #=> "my.custom.article.key"
    #
    # @return [String]
    attr_accessor :activity_key
    @activity_key = nil

    # Set or get custom fields for later processing
    #
    # @return [Hash]
    attr_accessor :activity_custom_fields
    @activity_custom_fields = {}

    # @!visibility private
    @@activity_hooks = {}

    # @!endgroup

    # Provides some global methods for every model class.
    class_methods do
      #
      # @since 1.0.0
      # @api private
      def set_public_activity_class_defaults
        self.activity_owner_global             = nil
        self.activity_recipient_global         = nil
        self.activity_params_global            = {}
        self.activity_hooks                    = {}
        self.activity_custom_fields_global     = {}
      end

      # Extracts a hook from the _:on_ option provided in
      # {Tracked::ClassMethods#tracked}. Returns nil when no hook exists for
      # given action
      # {Common#get_hook}
      #
      # @see Tracked#get_hook
      # @param key [String, Symbol] action to retrieve a hook for
      # @return [Proc, nil] callable hook or nil
      # @since 0.4.0
      # @api private
      def get_hook(key)
        key = key.to_sym
        if activity_hooks.key?(key) && activity_hooks[key].is_a?(Proc)
          activity_hooks[key]
        end
      end
    end
    #
    # Returns true if PublicActivity is enabled
    # globally and for this class.
    # @return [Boolean]
    # @api private
    # @since 0.5.0
    def public_activity_enabled?
      PublicActivity.enabled?
    end
    #
    # Shortcut for {ClassMethods#get_hook}
    # @param (see ClassMethods#get_hook)
    # @return (see ClassMethods#get_hook)
    # @since (see ClassMethods#get_hook)
    # @api (see ClassMethods#get_hook)
    def get_hook(key)
      self.class.get_hook(key)
    end

    # Calls hook safely.
    # If a hook for given action exists, calls it with model (self) and
    # controller (if available, see {StoreController})
    # @param key (see #get_hook)
    # @return [Boolean] if hook exists, it's decision, if there's no hook, true
    # @since 0.4.0
    # @api private
    def call_hook_safe(key)
      hook = get_hook(key)
      if hook
        # provides hook with model and controller
        hook.call(self, PublicActivity.get_controller)
      else
        true
      end
    end

    # Directly creates activity record in the database, based on supplied options.
    #
    # It's meant for creating custom activities while *preserving* *all*
    # *configuration* defined before. If you fire up the simplest of options:
    #
    #   current_user.create_activity(:avatar_changed)
    #
    # It will still gather data from any procs or symbols you passed as params
    # to {Tracked::ClassMethods#tracked}. It will ask the hooks you defined
    # whether to really save this activity.
    #
    # But you can also overwrite instance and global settings with your options:
    #
    #   @article.activity :owner => proc {|controller| controller.current_user }
    #   @article.create_activity(:commented_on, :owner => @user)
    #
    # And it's smart! It won't execute your proc, since you've chosen to
    # overwrite instance parameter _:owner_ with @user.
    #
    # [:key]
    #   The key will be generated from either:
    #   * the first parameter you pass that is not a hash (*action*)
    #   * the _:action_ option in the options hash (*action*)
    #   * the _:key_ option in the options hash (it has to be a full key,
    #     including model name)
    #   When you pass an *action* (first two options above), they will be
    #   added to parameterized model name:
    #
    #   Given Article model and instance: @article,
    #
    #     @article.create_activity :commented_on
    #     @article.activities.last.key # => "article.commented_on"
    #
    # For other parameters, see {Tracked#activity}, and "Instance options"
    # accessors at {Tracked}, information on hooks is available at
    # {Tracked::ClassMethods#tracked}.
    # @see #prepare_settings
    # @return [Model, nil] If created successfully, new activity
    # @since 0.4.0
    # @api public
    # @overload create_activity(action, options = {})
    #   @param [Symbol,String] action Name of the action
    #   @param [Hash] options Options with quality higher than instance options
    #     set in {Tracked#activity}
    #   @option options [Activist] :owner Owner
    #   @option options [Activist] :recipient Recipient
    #   @option options [Hash] :params Parameters, see
    #     {PublicActivity.resolve_value}
    # @overload create_activity(options = {})
    #   @param [Hash] options Options with quality higher than instance options
    #     set in {Tracked#activity}
    #   @option options [Symbol,String] :action Name of the action
    #   @option options [String] :key Full key
    #   @option options [Activist] :owner Owner
    #   @option options [Activist] :recipient Recipient
    #   @option options [Hash] :params Parameters, see
    #     {PublicActivity.resolve_value}
    def create_activity(*args)
      return unless public_activity_enabled?

      options = prepare_settings(*args)

      if call_hook_safe(options[:key].split('.').last)
        reset_activity_instance_options
        return PublicActivity::Adapter.create_activity(self, options)
      end

      nil
    end

    # Directly saves activity to database. Works the same as create_activity
    # but throws validation error for each supported ORM.
    #
    # @see #create_activity
    def create_activity!(*args)
      return unless public_activity_enabled?

      options = prepare_settings(*args)

      if call_hook_safe(options[:key].split('.').last)
        reset_activity_instance_options
        PublicActivity::Adapter.create_activity!(self, options)
      end
    end

    # Prepares settings used during creation of Activity record.
    # params passed directly to tracked model have priority over
    # settings specified in tracked() method
    #
    # @see #create_activity
    # @return [Hash] Settings with preserved options that were passed
    # @api private
    # @overload prepare_settings(action, options = {})
    #   @see #create_activity
    # @overload prepare_settings(options = {})
    #   @see #create_activity
    def prepare_settings(*args)
      raw_options = args.extract_options!
      action      = [args.first, raw_options.delete(:action)].compact.first
      key         = prepare_key(action, raw_options)

      raise NoKeyProvided, "No key provided for #{self.class.name}" unless key

      prepare_custom_fields(raw_options.except(:params)).merge(
        {
          key:        key,
          owner:      prepare_relation(:owner,     raw_options),
          recipient:  prepare_relation(:recipient, raw_options),
          parameters: prepare_parameters(raw_options),
        }
      )
    end

    # Prepares and resolves custom fields
    # users can pass to `tracked` method
    # @private
    def prepare_custom_fields(options)
      customs = self.class.activity_custom_fields_global.clone
      customs.merge!(activity_custom_fields) if activity_custom_fields
      customs.merge!(options)
      customs.each do  |k, v|
        customs[k] = PublicActivity.resolve_value(self, v)
      end
    end

    # Prepares i18n parameters that will
    # be serialized into the Activity#parameters column
    # @private
    def prepare_parameters(options)
      params = {}
      params.merge!(self.class.activity_params_global)
      params.merge!(activity_params) if activity_params
      params.merge!([options.delete(:parameters), options.delete(:params), {}].compact.first)
      params.each { |k, v| params[k] = PublicActivity.resolve_value(self, v) }
    end

    # Prepares relation to be saved
    # to Activity. Can be :recipient or :owner
    # @private
    def prepare_relation(name, options)
      PublicActivity.resolve_value(self,
        (options.key?(name) ? options[name] : (
          self.send("activity_#{name}") || self.class.send("activity_#{name}_global")
          )
        )
      )
    end

    # Helper method to serialize class name into relevant key
    # @return [String] the resulted key
    # @param [Symbol] or [String] the name of the operation to be done on class
    # @param [Hash] options to be used on key generation, defaults to {}
    def prepare_key(action, options = {})
      (
        options[:key] ||
        activity_key ||
        ((self.class.name.underscore.gsub('/', '_') + "." + action.to_s) if action)
      ).try(:to_s)
    end

    # Resets all instance options on the object
    # triggered by a successful #create_activity, should not be
    # called from any other place, or from application code.
    # @private
    def reset_activity_instance_options
      @activity_params = {}
      @activity_key = nil
      @activity_owner = nil
      @activity_recipient = nil
      @activity_custom_fields = {}
    end
  end
end


================================================
FILE: lib/public_activity/config.rb
================================================
# frozen_string_literal: true

require 'singleton'

module PublicActivity
  # Class used to initialize configuration object.
  class Config
    include ::Singleton

    # Evaluates given block to provide DSL configuration.
    # @example Initializer for Rails
    #   PublicActivity::Config.set do
    #     orm :mongo_mapper
    #     enabled false
    #     table_name "activities"
    #   end
    def self.set(&block)
      b = Block.new
      b.instance_eval(&block)
      instance
      orm(b.orm) unless b.orm.nil?
      enabled(b.enabled) unless b.enabled.nil?
      table_name(b.table_name) unless b.table_name.nil?
    end

    # alias for {#orm}
    # @see #orm
    def self.orm=(orm = nil)
      orm(orm)
    end

    # alias for {#enabled}
    # @see #enabled
    def self.enabled=(value = nil)
      enabled(value)
    end

    # instance version of {Config#orm}
    # @see Config#orm
    def orm(orm = nil)
      self.class.orm(orm)
    end

    # instance version of {Config#table_name}
    # @see Config#orm
    def table_name(name = nil)
      self.class.table_name(name)
    end

    # instance version of {Config#enabled}
    # @see Config#orm
    def enabled(value = nil)
      self.class.enabled(value)
    end

    # Set the ORM for use by PublicActivity.
    def self.orm(orm = nil)
      if orm.nil?
        Thread.current[:public_activity_orm] || :active_record
      else
        Thread.current[:public_activity_orm] = orm.to_sym
      end
    end

    def self.table_name(name = nil)
      if name.nil?
        Thread.current[:public_activity_table_name] || "activities"
      else
        Thread.current[:public_activity_table_name] = name
      end
    end

    def self.enabled(value = nil)
      if value.nil?
        val = Thread.current[:public_activity_enabled]
        val.nil? ? true : val
      else
        Thread.current[:public_activity_enabled] = value
      end
    end

    # Provides simple DSL for the config block.
    class Block
      # @see Config#orm
      def orm(orm = nil)
        @orm = (orm ? orm.to_sym : false) || @orm
      end

      # Decides whether to enable PublicActivity.
      # @param en [Boolean] Enabled?
      def enabled(value = nil)
        @enabled = (value.nil? ? @enabled : value)
      end

      # Sets the table_name for the model
      def table_name(name = nil)
        @table_name = (name.nil? ? @table_name : name)
      end
    end
  end
end


================================================
FILE: lib/public_activity/models/activist.rb
================================================
# frozen_string_literal: true

module PublicActivity
  # Provides helper methods for selecting activities from a user.
  module Activist
    # Delegates to configured ORM.
    def self.included(base)
      base.extend PublicActivity.inherit_orm('Activist')
    end
  end
end


================================================
FILE: lib/public_activity/models/activity.rb
================================================
# frozen_string_literal: true

module PublicActivity
  class Activity < inherit_orm
  end
end


================================================
FILE: lib/public_activity/models/adapter.rb
================================================
# frozen_string_literal: true

module PublicActivity
  # Loads database-specific routines for use by PublicActivity.
  class Adapter < inherit_orm('Adapter')
  end
end


================================================
FILE: lib/public_activity/models/trackable.rb
================================================
# frozen_string_literal: true

module PublicActivity
  # Provides association for activities bound to this object by *trackable*.
  module Trackable
    # Delegates to ORM.
    def self.included(base)
      base.extend PublicActivity.inherit_orm('Trackable')
    end
  end
end


================================================
FILE: lib/public_activity/orm/active_record/activist.rb
================================================
# frozen_string_literal: true

module PublicActivity
  module ORM
    module ActiveRecord
      # Module extending classes that serve as owners
      module Activist
        # Adds ActiveRecord associations to model to simplify fetching
        # so you can list activities performed by the owner.
        # It is completely optional. Any model can be an owner to an activity
        # even without being an explicit activist.
        #
        # == Usage:
        # In model:
        #
        #   class User < ActiveRecord::Base
        #     include PublicActivity::Model
        #     activist
        #   end
        #
        # In controller:
        #   User.first.activities_as_owner
        #   User.first.activities_as_recipient
        #
        def activist
          has_many :activities_as_owner,
                   class_name: '::PublicActivity::Activity',
                   as: :owner
          has_many :activities_as_recipient,
                   class_name: '::PublicActivity::Activity',
                   as: :recipient
        end
      end
    end
  end
end


================================================
FILE: lib/public_activity/orm/active_record/activity.rb
================================================
# frozen_string_literal: true

module PublicActivity
  unless defined? ::PG::ConnectionBad
    module ::PG
      class ConnectionBad < Exception; end
    end
  end
  unless defined? Mysql2::Error::ConnectionError
    module Mysql2
      module Error
        class ConnectionError < Exception; end
      end
    end
  end

  module ORM
    module ActiveRecord
      # The ActiveRecord model containing
      # details about recorded activity.
      class Activity < ::ActiveRecord::Base
        include Renderable
        self.table_name = PublicActivity.config.table_name
        self.abstract_class = true

        # Define polymorphic association to the parent
        belongs_to :trackable, polymorphic: true

        with_options(optional: true) do
          # Define ownership to a resource responsible for this activity
          belongs_to :owner, polymorphic: true
          # Define ownership to a resource targeted by this activity
          belongs_to :recipient, polymorphic: true
        end

        # Serialize parameters Hash
        begin
          if table_exists?
            unless %i[json jsonb hstore].include?(columns_hash['parameters'].type)
              if ::ActiveRecord.version.release < Gem::Version.new('7.1')
                serialize :parameters, Hash
              else
                serialize :parameters, coder: YAML, type: Hash
              end
            end
          else
            warn("[WARN] table #{name} doesn't exist. Skipping PublicActivity::Activity#parameters's serialization")
          end
        rescue ::ActiveRecord::NoDatabaseError
          warn("[WARN] database doesn't exist. Skipping PublicActivity::Activity#parameters's serialization")
        rescue ::ActiveRecord::ConnectionNotEstablished, ::PG::ConnectionBad, Mysql2::Error::ConnectionError
          warn("[WARN] couldn't connect to database. Skipping PublicActivity::Activity#parameters's serialization")
        end
      end
    end
  end
end


================================================
FILE: lib/public_activity/orm/active_record/adapter.rb
================================================
# frozen_string_literal: true

module PublicActivity
  module ORM
    # Support for ActiveRecord for PublicActivity. Used by default and supported
    # officialy.
    module ActiveRecord
      # Provides ActiveRecord specific, database-related routines for use by
      # PublicActivity.
      class Adapter
        # Creates the activity on `trackable` with `options`
        def self.create_activity(trackable, options)
          trackable.activities.create options
        end

        # Creates activity on `trackable` with `options`; throws error on validation failure
        def self.create_activity!(trackable, options)
          trackable.activities.create! options
        end
      end
    end
  end
end


================================================
FILE: lib/public_activity/orm/active_record/trackable.rb
================================================
# frozen_string_literal: true

module PublicActivity
  module ORM
    module ActiveRecord
      # Implements {PublicActivity::Trackable} for ActiveRecord
      # @see PublicActivity::Trackable
      module Trackable
        # Creates an association for activities where self is the *trackable*
        # object.
        def self.extended(base)
          base.has_many :activities,
                        class_name: '::PublicActivity::Activity',
                        as: :trackable
        end
      end
    end
  end
end


================================================
FILE: lib/public_activity/orm/active_record.rb
================================================
# frozen_string_literal: true

require 'active_record'
require_relative 'active_record/activity'
require_relative 'active_record/adapter'
require_relative 'active_record/activist'
require_relative 'active_record/trackable'


================================================
FILE: lib/public_activity/orm/mongo_mapper/activist.rb
================================================
# frozen_string_literal: true

module PublicActivity
  module ORM
    module MongoMapper
      # Module extending classes that serve as owners
      module Activist
        # Adds MongoMapper associations to model to simplify fetching
        # so you can list activities performed by the owner.
        # It is completely optional. Any model can be an owner to an activity
        # even without being an explicit activist.
        #
        # == Usage:
        # In model:
        #
        #   class User
        #     include MongoMapper::Document
        #     include PublicActivity::Model
        #     activist
        #   end
        #
        # In controller:
        #   User.first.activities
        #
        def activist
          many :activities_as_owner,
            :class_name => "::PublicActivity::Activity",
            :as => :owner
          many :activities_as_recipient,
            :class_name => "::PublicActivity::Activity",
            :as => :recipient
        end
      end
    end
  end
end


================================================
FILE: lib/public_activity/orm/mongo_mapper/activity.rb
================================================
# frozen_string_literal: true

require 'mongo_mapper'
require 'active_support/core_ext'

module PublicActivity
  module ORM
    module MongoMapper
      # The MongoMapper document containing
      # details about recorded activity.
      class Activity
        include ::MongoMapper::Document
        include Renderable

        class SymbolHash < Hash
          def self.from_mongo(value)
            value.symbolize_keys unless value.nil?
          end
        end

        # Define polymorphic association to the parent
        belongs_to :trackable,  polymorphic: true
        # Define ownership to a resource responsible for this activity
        belongs_to :owner,      polymorphic: true
        # Define ownership to a resource targeted by this activity
        belongs_to :recipient,  polymorphic: true

        key :key,         String
        key :parameters,  SymbolHash

        timestamps!
      end
    end
  end
end


================================================
FILE: lib/public_activity/orm/mongo_mapper/adapter.rb
================================================
# frozen_string_literal: true

module PublicActivity
  module ORM
    module MongoMapper
      class Adapter
        # Creates the activity on `trackable` with `options`
        def self.create_activity(trackable, options)
          trackable.activities.create options
        end

        # Creates activity on `trackable` with `options`; throws error on validation failure
        def self.create_activity!(trackable, options)
          trackable.activities.create! options
        end
      end
    end
  end
end


================================================
FILE: lib/public_activity/orm/mongo_mapper/trackable.rb
================================================
# frozen_string_literal: true

module PublicActivity
  module ORM
    module MongoMapper
      module Trackable
        def self.extended(base)
          base.many :activities, :class_name => "::PublicActivity::Activity", order: :created_at.asc, :as => :trackable
        end
      end
    end
  end
end


================================================
FILE: lib/public_activity/orm/mongo_mapper.rb
================================================
# frozen_string_literal: true

require_relative "mongo_mapper/activity.rb"
require_relative "mongo_mapper/adapter.rb"
require_relative "mongo_mapper/activist.rb"
require_relative "mongo_mapper/trackable.rb"


================================================
FILE: lib/public_activity/orm/mongoid/activist.rb
================================================
# frozen_string_literal: true

module PublicActivity
  module ORM
    module Mongoid
      # Module extending classes that serve as owners
      module Activist
        # Adds ActiveRecord associations to model to simplify fetching
        # so you can list activities performed by the owner.
        # It is completely optional. Any model can be an owner to an activity
        # even without being an explicit activist.
        #
        # == Usage:
        # In model:
        #
        #   class User < ActiveRecord::Base
        #     include PublicActivity::Model
        #     activist
        #   end
        #
        # In controller:
        #   User.first.activities
        #
        def activist
          has_many :activities_as_owner,
            :class_name => "::PublicActivity::Activity",
            :inverse_of => :owner

          has_many :activities_as_recipient,
            :class_name => "::PublicActivity::Activity",
            :inverse_of => :recipient
        end
      end
    end
  end
end


================================================
FILE: lib/public_activity/orm/mongoid/activity.rb
================================================
# frozen_string_literal: true

require 'mongoid'

module PublicActivity
  module ORM
    module Mongoid
      # The ActiveRecord model containing
      # details about recorded activity.
      class Activity
        include ::Mongoid::Document
        include ::Mongoid::Timestamps
        include ::Mongoid::Attributes::Dynamic if ::Mongoid::VERSION.split('.')[0].to_i >= 4
        include Renderable

        if ::Mongoid::VERSION.split('.')[0].to_i >= 7
          opts = { polymorphic: true, optional: false }
        else
          opts = { polymorphic: true }
        end

        # Define polymorphic association to the parent
        belongs_to :trackable,  opts
        # Define ownership to a resource responsible for this activity
        belongs_to :owner,      opts
        # Define ownership to a resource targeted by this activity
        belongs_to :recipient,  opts

        field :key,         type: String
        field :parameters,  type: Hash
      end
    end
  end
end


================================================
FILE: lib/public_activity/orm/mongoid/adapter.rb
================================================
# frozen_string_literal: true

module PublicActivity
  module ORM
    module Mongoid
      class Adapter
        # Creates the activity on `trackable` with `options`
        def self.create_activity(trackable, options)
          trackable.activities.create options
        end

        # Creates activity on `trackable` with `options`; throws error on validation failure
        def self.create_activity!(trackable, options)
          trackable.activities.create! options
        end
      end
    end
  end
end


================================================
FILE: lib/public_activity/orm/mongoid/trackable.rb
================================================
# frozen_string_literal: true

module PublicActivity
  module ORM
    module Mongoid
      module Trackable
        def self.extended(base)
          base.has_many :activities, :class_name => "::PublicActivity::Activity", :as => :trackable
        end
      end
    end
  end
end


================================================
FILE: lib/public_activity/orm/mongoid.rb
================================================
# frozen_string_literal: true

require_relative "mongoid/activity.rb"
require_relative "mongoid/adapter.rb"
require_relative "mongoid/activist.rb"
require_relative "mongoid/trackable.rb"


================================================
FILE: lib/public_activity/renderable.rb
================================================
# frozen_string_literal: true

module PublicActivity
  # Provides logic for rendering activities. Handles both i18n strings
  # support and smart partials rendering (different templates per activity key).
  module Renderable
    # Virtual attribute returning text description of the activity
    # using the activity's key to translate using i18n.
    def text(params = {})
      # TODO: some helper for key transformation for two supported formats
      k = key.split('.')
      k.unshift('activity') if k.first != 'activity'
      k = k.join('.')

      translate_params = parameters.merge(params) || {}
      I18n.t(k, **translate_params)
    end

    # Renders activity from views.
    #
    # @param [ActionView::Base] context
    # @return [nil] nil
    #
    # Renders activity to the given ActionView context with included
    # AV::Helpers::RenderingHelper (most commonly just ActionView::Base)
    #
    # The *preferred* *way* of rendering activities is
    # to provide a template specifying how the rendering should be happening.
    # However, one may choose using _I18n_ based approach when developing
    # an application that supports plenty of languages.
    #
    # If partial view exists that matches the *key* attribute
    # renders that partial with local variables set to contain both
    # Activity and activity_parameters (hash with indifferent access)
    #
    # Otherwise, it outputs the I18n translation to the context
    # @example Render a list of all activities from a view (erb)
    #   <ul>
    #     <% for activity in PublicActivity::Activity.all %>
    #      <li><%= render_activity(activity) %></li>
    #     <% end %>
    #   </ul>
    #
    # = Layouts
    # You can supply a layout that will be used for activity partials
    # with :layout param.
    # Keep in mind that layouts for partials are also partials.
    # @example Supply a layout
    #   # in views:
    #   #   All examples look for a layout in app/views/layouts/_activity.erb
    #    render_activity @activity, :layout => "activity"
    #    render_activity @activity, :layout => "layouts/activity"
    #    render_activity @activity, :layout => :activity
    #
    #   # app/views/layouts/_activity.erb
    #   <p><%= a.created_at %></p>
    #   <%= yield %>
    #
    # == Custom Layout Location
    # You can customize the layout directory by supplying :layout_root
    # or by using an absolute path.
    #
    # @example Declare custom layout location
    #
    #   # Both examples look for a layout in "app/views/custom/_layout.erb"
    #
    #    render_activity @activity, :layout_root => "custom"
    #    render_activity @activity, :layout      => "/custom/layout"
    #
    # = Creating a template
    # To use templates for formatting how the activity should render,
    # create a template based on activity key, for example:
    #
    # Given a key _activity.article.create_, create directory tree
    # _app/views/public_activity/article/_ and create the _create_ partial there
    #
    # Note that if a key consists of more than three parts splitted by commas, your
    # directory structure will have to be deeper, for example:
    #   activity.article.comments.destroy => app/views/public_activity/articles/comments/_destroy.html.erb
    #
    # == Custom Directory
    # You can override the default `public_directory` template root with the :root parameter
    #
    # @example Custom template root
    #    # look for templates inside of /app/views/custom instead of /app/views/public_directory
    #    render_activity @activity, :root => "custom"
    #
    # == Variables in templates
    # From within a template there are two variables at your disposal:
    # * activity (aliased as *a* for a shortcut)
    # * params   (aliased as *p*) [converted into a HashWithIndifferentAccess]
    #
    # @example Template for key: _activity.article.create_ (erb)
    #   <p>
    #     Article <strong><%= p[:name] %></strong>
    #     was written by <em><%= p["author"] %></em>
    #     <%= distance_of_time_in_words_to_now(a.created_at) %>
    #   </p>
    def render(context, params = {})
      partial_root  = params.delete(:root)         || 'public_activity'
      partial_path  = nil
      layout_root   = params.delete(:layout_root)  || 'layouts'

      if params.has_key? :display
        if params[:display].to_sym == :"i18n"
          text = self.text(params)
          return context.render :text => text, :plain => text
        else
          partial_path = File.join(partial_root, params[:display].to_s)
        end
      end

      context.render(
        params.merge({
          :partial => prepare_partial(partial_root, partial_path),
          :layout  => prepare_layout(layout_root, params.delete(:layout)),
          :locals  => prepare_locals(params)
        })
      )
    end

    def prepare_partial(root, path)
      path || self.template_path(self.key, root)
    end

    def prepare_locals(params)
      locals = params.delete(:locals) || Hash.new

      controller  = PublicActivity.get_controller
      prepared_params = prepare_parameters(params)
      locals.merge(
        {
          :a              => self,
          :activity       => self,
          :controller     => controller,
          :current_user   => controller.respond_to?(:current_user) ? controller.current_user : nil,
          :p              => prepared_params,
          :params         => prepared_params
        }
      )
    end

    def prepare_layout(root, layout)
      if layout
        path = layout.to_s
        unless path.start_with?(root) || path.start_with?("/")
          return File.join(root, path)
        end
      end
      layout
    end

    def prepare_parameters(params)
      if self.parameters
        @prepared_params ||= self.parameters.with_indifferent_access.merge(params)
      else
        @prepared_params ||= params
      end
    end

    protected

    # Builds the path to template based on activity key
    def template_path(key, partial_root)
      path = key.split(".")
      path.delete_at(0) if path[0] == "activity"
      path.unshift partial_root
      path.join("/")
    end
  end
end


================================================
FILE: lib/public_activity/roles/deactivatable.rb
================================================
# frozen_string_literal: true

module PublicActivity
  # Enables per-class disabling of PublicActivity functionality.
  module Deactivatable
    extend ActiveSupport::Concern

    included do
      class_attribute :public_activity_enabled_for_model
      set_public_activity_class_defaults
    end

    # Returns true if PublicActivity is enabled
    # globally and for this class.
    # @return [Boolean]
    # @api private
    # @since 0.5.0
    # overrides the method from Common
    def public_activity_enabled?
      PublicActivity.enabled? && self.class.public_activity_enabled_for_model
    end

    # Provides global methods to disable or enable PublicActivity on a per-class
    # basis.
    module ClassMethods
      # Switches public_activity off for this class
      def public_activity_off
        self.public_activity_enabled_for_model = false
      end

      # Switches public_activity on for this class
      def public_activity_on
        self.public_activity_enabled_for_model = true
      end

      # @since 1.0.0
      # @api private
      def set_public_activity_class_defaults
        super
        self.public_activity_enabled_for_model = true
      end
    end
  end
end


================================================
FILE: lib/public_activity/roles/tracked.rb
================================================
# frozen_string_literal: true

module PublicActivity
  # Main module extending classes we want to keep track of.
  module Tracked
    extend ActiveSupport::Concern
    # A shortcut method for setting custom key, owner and parameters of {Activity}
    # in one line. Accepts a hash with 3 keys:
    # :key, :owner, :params. You can specify all of them or just the ones you want to overwrite.
    #
    # == Options
    #
    # [:key]
    #   See {Common#activity_key}
    # [:owner]
    #   See {Common#activity_owner}
    # [:params]
    #   See {Common#activity_params}
    # [:recipient]
    #   Set the recipient for this activity. Useful for private notifications, which should only be visible to a certain user. See {Common#activity_recipient}.
    # @example
    #
    #   @article = Article.new
    #   @article.title = "New article"
    #   @article.activity :key => "my.custom.article.key", :owner => @article.author, :params => {:title => @article.title}
    #   @article.save
    #   @article.activities.last.key #=> "my.custom.article.key"
    #   @article.activities.last.parameters #=> {:title => "New article"}
    #
    # @param options [Hash] instance options to set on the tracked model
    # @return [nil]
    def activity(options = {})
      rest = options.clone
      self.activity_key           = rest.delete(:key) if rest[:key]
      self.activity_owner         = rest.delete(:owner) if rest[:owner]
      self.activity_params        = rest.delete(:params) if rest[:params]
      self.activity_recipient     = rest.delete(:recipient) if rest[:recipient]
      self.activity_custom_fields = rest if rest.count > 0
      nil
    end

    # Module with basic +tracked+ method that enables tracking models.
    class_methods do
      # Adds required callbacks for creating and updating
      # tracked models and adds +activities+ relation for listing
      # associated activities.
      #
      # == Parameters:
      # [:owner]
      #   Specify the owner of the {Activity} (person responsible for the action).
      #   It can be a Proc, Symbol or an ActiveRecord object:
      #   == Examples:
      #
      #    tracked :owner => :author
      #    tracked :owner => proc {|o| o.author}
      #
      #   Keep in mind that owner relation is polymorphic, so you can't just
      #   provide id number of the owner object.
      # [:recipient]
      #   Specify the recipient of the {Activity}
      #   It can be a Proc, Symbol, or an ActiveRecord object
      #   == Examples:
      #
      #    tracked :recipient => :author
      #    tracked :recipient => proc {|o| o.author}
      #
      #   Keep in mind that recipient relation is polymorphic, so you can't just
      #   provide id number of the owner object.
      # [:params]
      #   Accepts a Hash with custom parameters you want to pass to i18n.translate
      #   method. It is later used in {Renderable#text} method.
      #   == Example:
      #    class Article < ActiveRecord::Base
      #      include PublicActivity::Model
      #      tracked :params => {
      #          :title => :title,
      #          :author_name => "Michael",
      #          :category_name => proc {|controller, model_instance| model_instance.category.name},
      #          :summary => proc {|controller, model_instance| truncate(model.text, :length => 30)}
      #      }
      #    end
      #
      #   Values in the :params hash can either be an *exact* *value*, a *Proc/Lambda* executed before saving the activity or a *Symbol*
      #   which is a an attribute or a method name executed on the tracked model's instance.
      #
      #   Everything specified here has a lower priority than parameters
      #   specified directly in {#activity} method.
      #   So treat it as a place where you provide 'default' values or where you
      #   specify what data should be gathered for every activity.
      #   For more dynamic settings refer to {Activity} model documentation.
      # [:skip_defaults]
      #   Disables recording of activities on create/update/destroy leaving that to programmer's choice. Check {PublicActivity::Common#create_activity}
      #   for a guide on how to manually record activities.
      # [:only]
      #   Accepts a symbol or an array of symbols, of which any combination of the three is accepted:
      #   * _:create_
      #   * _:update_
      #   * _:destroy_
      #   Selecting one or more of these will make PublicActivity create activities
      #   automatically for the tracked model on selected actions.
      #
      #   Resulting activities will have have keys assigned to, respectively:
      #   * _article.create_
      #   * _article.update_
      #   * _article.destroy_
      #   Since only three options are valid,
      #   see _:except_ option for a shorter version
      # [:except]
      #   Accepts a symbol or an array of symbols with values like in _:only_, above.
      #   Values provided will be subtracted from all default actions:
      #   (create, update, destroy).
      #
      #   So, passing _create_ would track and automatically create
      #   activities on _update_ and _destroy_ actions,
      #   but not on the _create_ action.
      # [:on]
      #   Accepts a Hash with key being the *action* on which to execute *value* (proc)
      #   Currently supported only for CRUD actions which are enabled in _:only_
      #   or _:except_ options on this method.
      #
      #   Key-value pairs in this option define callbacks that can decide
      #   whether to create an activity or not. Procs have two attributes for
      #   use: _model_ and _controller_. If the proc returns true, the activity
      #   will be created, if not, then activity will not be saved.
      #
      #   == Example:
      #     # app/models/article.rb
      #     tracked :on => {:update => proc {|model, controller| model.published? }}
      #
      #   In the example above, given a model Article with boolean column _published_.
      #   The activities with key _article.update_ will only be created
      #   if the published status is set to true on that article.
      # @param opts [Hash] options
      # @return [nil] options
      def tracked(opts = {})
        options = opts.clone

        include_default_actions(options)

        assign_globals       options
        assign_hooks         options
        assign_custom_fields options

        nil
      end

      def include_default_actions(options)
        defaults = {
          create:  Creation,
          destroy: Destruction,
          update:  Update
        }

        return if options[:skip_defaults] == true

        modules = if options[:except]
          defaults.except(*options[:except])
        elsif options[:only]
          defaults.slice(*options[:only])
        else
          defaults
        end

        modules.each_value { |mod| include mod }
      end

      def available_options
        %i[skip_defaults only except on owner recipient params].freeze
      end

      def assign_globals(options)
        %i[owner recipient params].each do |key|
          next unless options[key]

          send("activity_#{key}_global=".to_sym, options.delete(key))
        end
      end

      def assign_hooks(options)
        return unless options[:on].is_a?(Hash)

        self.activity_hooks = options[:on].select { |_, v| v.is_a? Proc }.symbolize_keys
      end

      def assign_custom_fields(options)
        options.except(*available_options).each do |k, v|
          activity_custom_fields_global[k] = v
        end
      end
    end
  end
end


================================================
FILE: lib/public_activity/testing.rb
================================================
# frozen_string_literal: true

# This file provides functionality for testing your code with public_activity
# activated or deactivated.
# This file should only be required in test/spec code!
#
# To enable PublicActivity testing capabilities do:
#   require 'public_activity/testing'
module PublicActivity
  # Execute the code block with PublicActiviy active
  #
  # Example usage:
  #   PublicActivity.with_tracking do
  #     # your test code here
  #   end
  def self.with_tracking
    current = PublicActivity.config.enabled
    PublicActivity.config.enabled(true)
    yield
  ensure
    PublicActivity.config.enabled(current)
  end

  # Execute the code block with PublicActiviy deactive
  #
  # Example usage:
  #   PublicActivity.without_tracking do
  #     # your test code here
  #   end
  def self.without_tracking
    current = PublicActivity.enabled?
    PublicActivity.config.enabled(false)
    yield
  ensure
    PublicActivity.config.enabled(current)
  end
end


================================================
FILE: lib/public_activity/utility/store_controller.rb
================================================
# frozen_string_literal: true

module PublicActivity
  class << self
    # Setter for remembering controller instance
    def set_controller(controller)
      Thread.current[:public_activity_controller] = controller
    end

    # Getter for accessing the controller instance
    def get_controller
      Thread.current[:public_activity_controller]
    end
  end

  # Module included in controllers to allow p_a access to controller instance
  module StoreController
    extend ActiveSupport::Concern

    included do
      around_action :store_controller_for_public_activity if     respond_to?(:around_action)
      around_filter :store_controller_for_public_activity unless respond_to?(:around_action)
    end

    def store_controller_for_public_activity
      PublicActivity.set_controller(self)
      yield
    ensure
      PublicActivity.set_controller(nil)
    end
  end
end


================================================
FILE: lib/public_activity/utility/view_helpers.rb
================================================
# frozen_string_literal: true

# Provides a shortcut from views to the rendering method.
module PublicActivity
  # Module extending ActionView::Base and adding `render_activity` helper.
  module ViewHelpers
    # View helper for rendering an activity, calls {PublicActivity::Activity#render} internally.
    def render_activity activities, options = {}
      if activities.is_a? PublicActivity::Activity
        activities.render self, options
      elsif activities.respond_to?(:map)
        # depend on ORMs to fetch as needed
        # maybe we can support Postgres streaming with this?
        activities.map {|activity| activity.render self, options.dup }.join.html_safe
      end
    end
    alias_method :render_activities, :render_activity

    # Helper for setting content_for in activity partial, needed to
    # flush remains in between partial renders.
    def single_content_for(name, content = nil, &block)
      @view_flow.set(name, ActiveSupport::SafeBuffer.new)
      content_for(name, content, &block)
    end
  end
end

ActiveSupport.on_load(:action_view) do
  include PublicActivity::ViewHelpers
end


================================================
FILE: lib/public_activity/version.rb
================================================
# frozen_string_literal: true

module PublicActivity
  VERSION = '3.0.2'
end


================================================
FILE: lib/public_activity.rb
================================================
# frozen_string_literal: true

require 'active_support'
require 'logger'
require 'action_view'
# +public_activity+ keeps track of changes made to models
# and allows you to display them to the users.
#
# Check {PublicActivity::Tracked::ClassMethods#tracked} for more details about customizing and specifying
# ownership to users.
module PublicActivity
  extend ActiveSupport::Concern
  extend ActiveSupport::Autoload

  autoload :Activity,     'public_activity/models/activity'
  autoload :Activist,     'public_activity/models/activist'
  autoload :Adapter,      'public_activity/models/adapter'
  autoload :Trackable,    'public_activity/models/trackable'
  autoload :Common
  autoload :Config
  autoload :Creation,     'public_activity/actions/creation.rb'
  autoload :Deactivatable,'public_activity/roles/deactivatable.rb'
  autoload :Destruction,  'public_activity/actions/destruction.rb'
  autoload :Renderable
  autoload :Tracked,      'public_activity/roles/tracked.rb'
  autoload :Update,       'public_activity/actions/update.rb'
  autoload :VERSION

  # Switches PublicActivity on or off.
  # @param value [Boolean]
  # @since 0.5.0
  def self.enabled=(value)
    config.enabled(value)
  end

  # Returns `true` if PublicActivity is on, `false` otherwise.
  # Enabled by default.
  # @return [Boolean]
  # @since 0.5.0
  def self.enabled?
    config.enabled
  end

  # Returns PublicActivity's configuration object.
  # @since 0.5.0
  def self.config
    @@config ||= PublicActivity::Config.instance
  end

  # Method used to choose which ORM to load
  # when PublicActivity::Activity class is being autoloaded
  def self.inherit_orm(model = 'Activity')
    orm = PublicActivity.config.orm
    require "public_activity/orm/#{orm}"
    "PublicActivity::ORM::#{orm.to_s.classify}::#{model}".constantize
  end

  # Module to be included in ActiveRecord models. Adds required functionality.
  module Model
    extend ActiveSupport::Concern

    included do
      include Common
      include Deactivatable
      include Tracked
      include Activist # optional associations by recipient|owner
    end
  end
end

require 'public_activity/utility/store_controller'
require 'public_activity/utility/view_helpers'


================================================
FILE: public_activity.gemspec
================================================
# frozen_string_literal: true

$LOAD_PATH.push File.expand_path('../lib', __FILE__)
require 'public_activity/version'

Gem::Specification.new do |s|
  s.name = 'public_activity'
  s.version = PublicActivity::VERSION
  s.platform = Gem::Platform::RUBY
  s.authors = ['Juri Hahn', 'Piotrek Okoński', 'Kuba Okoński']
  s.email = 'juri.hahn+public-activity@gmail.com'
  s.homepage = 'https://github.com/public-activity/public_activity'
  s.summary = 'Easy activity tracking for ActiveRecord models'
  s.description = 'Easy activity tracking for your ActiveRecord models. Provides Activity model with details about actions performed by your users, like adding comments, responding etc.'
  s.license = 'MIT'
  s.metadata = {
    "bug_tracker_uri"   => "https://github.com/public-activity/public_activity/issues",
    'changelog_uri'     => 'https://github.com/public-activity/public_activity/blob/main/CHANGELOG.md',
    "documentation_uri" => "https://rubydoc.info/gems/public_activity",
    "homepage_uri"      => s.homepage,
    "source_code_uri"   => "https://github.com/public-activity/public_activity",
    "rubygems_mfa_required" => "true",
  }

  s.files = `git ls-files lib`.split("\n") + ['Gemfile', 'Rakefile', 'README.md', 'MIT-LICENSE']
  s.test_files = `git ls-files test`.split("\n")
  s.require_paths = ['lib']

  s.required_ruby_version = '>= 3.0.0'

  s.post_install_message = File.read('UPGRADING') if File.exist?('UPGRADING')

  s.add_dependency 'actionpack', '>= 6.1'
  s.add_dependency 'i18n', '>= 0.5.0'
  s.add_dependency 'railties', '>= 6.1'

  ENV['PA_ORM'] ||= 'active_record'
  case ENV['PA_ORM']
  when 'active_record'
    s.add_dependency 'activerecord', '>= 6.1'
  when 'mongoid'
    s.add_dependency 'mongoid',      '>= 4.0'
  when 'mongo_mapper'
    s.add_dependency 'bson_ext'
    s.add_dependency 'mongo', '<= 1.9.2'
    s.add_dependency 'mongo_mapper', '>= 0.12.0'
  end

  s.add_development_dependency 'appraisal'
  s.add_development_dependency 'minitest'
  s.add_development_dependency 'mocha'
  s.add_development_dependency 'pry'
  s.add_development_dependency 'redcarpet'
  s.add_development_dependency 'simplecov'
  s.add_development_dependency 'sqlite3', '~> 1.4'
  s.add_development_dependency 'test-unit'
  s.add_development_dependency 'yard'
  s.add_development_dependency 'rake'
end


================================================
FILE: public_activity.sublime-project
================================================
{
  "folders":
  [
    {
      "path": "./",
      "folder_exclude_patterns": ["coverage", ".yardoc", "doc"]
    }
  ],
  "settings":
  {
    "tab_size": 2,
    "translate_tabs_to_spaces": true,
    "trim_trailing_white_space_on_save": true
  },
  "build_systems":
  [
    {
      "name": "PublicActivity Test Suite",
      "linux": {
        "working_dir": "$project_dir",
        "cmd": ["bundle", "exec", "rake", "test"]
      },
      "selector": "source.ruby"
    }
  ]
}


================================================
FILE: test/migrations/002_create_articles.rb
================================================
# frozen_string_literal: true

class CreateArticles < ActiveRecord::Migration[6.1]
  def self.up
    create_table :articles do |t|
      t.string :name
      t.boolean :published
      t.belongs_to :user
      t.timestamps
    end
  end
end


================================================
FILE: test/migrations/003_create_users.rb
================================================
# frozen_string_literal: true

class CreateUsers < ActiveRecord::Migration[6.1]
  def self.up
    create_table :users do |t|
      t.string :name
      t.timestamps
    end
  end
end


================================================
FILE: test/migrations/004_add_nonstandard_to_activities.rb
================================================
# frozen_string_literal: true

class AddNonstandardToActivities < ActiveRecord::Migration[6.1]
  def change
    change_table :activities do |t|
      t.string :nonstandard
    end
  end
end


================================================
FILE: test/mongo_mapper.yml
================================================
test:
  host: 127.0.0.1
  port: 27017
  database: public_activity_test

================================================
FILE: test/mongoid.yml
================================================
test:
  clients:
    default:
      hosts:
        - 127.0.0.1:27017
      database: public_activity_test


================================================
FILE: test/test_activist.rb
================================================
# frozen_string_literal: true

require 'test_helper'

describe PublicActivity::Activist do
  it 'adds owner association' do
    klass = article
    assert_respond_to klass, :activist
    klass.activist
    assert_respond_to klass.new, :activities

    case ENV['PA_ORM']
    when 'active_record'
      assert_equal klass.reflect_on_association(:activities_as_owner).options[:as], :owner
    when 'mongoid'
      assert_equal klass.reflect_on_association(:activities_as_owner).options[:inverse_of], :owner
    when 'mongo_mapper'
      assert_equal klass.associations[:activities_as_owner].options[:as], :owner
    end

    if ENV['PA_ORM'] == 'mongo_mapper'
      assert_equal klass.associations[:activities_as_owner].options[:class_name], '::PublicActivity::Activity'
    else
      assert_equal klass.reflect_on_association(:activities_as_owner).options[:class_name], '::PublicActivity::Activity'
    end
  end

  it 'returns activities from association' do
    case PublicActivity::Config.orm
    when :active_record
      class ActivistUser < ActiveRecord::Base
        include PublicActivity::Model
        self.table_name = 'users'
        activist
      end
    when :mongoid
      class ActivistUser
        include Mongoid::Document
        include PublicActivity::Model
        activist

        field :name, type: String
      end
    when :mongo_mapper
      class ActivistUser
        include MongoMapper::Document
        include PublicActivity::Model
        activist

        key :name, String
      end
    end
    owner = ActivistUser.create(name: 'Peter Pan')
    a = article(owner: owner).new
    a.save

    assert_equal owner.activities_as_owner.length, 1
  end
end


================================================
FILE: test/test_activity.rb
================================================
# frozen_string_literal: true

require 'test_helper'

describe 'PublicActivity::Activity Rendering' do
  describe '#text' do
    subject { PublicActivity::Activity.new(key: 'activity.test', parameters: { one: 1 }) }

    specify '#text uses translations' do
      subject.save
      I18n.config.backend.store_translations(:en, activity: { test: '%{one} %{two}' })
      assert_equal subject.text(two: 2), '1 2'
      assert_equal subject.parameters, one: 1
    end
  end

  describe '#render' do
    subject do
      PublicActivity::Activity.new(key: 'activity.test', parameters: { one: 1 }).tap(&:save)
    end

    let(:template_output) { "<strong>1, 2</strong>\n<em>activity.test, #{subject.id}</em>\n" }
    before { @controller.class.prepend_view_path File.expand_path('views', __dir__) }

    it 'uses view partials when available' do
      PublicActivity.set_controller(Struct.new(:current_user).new('fake'))
      subject.render(self, two: 2)
      assert_equal rendered, "#{template_output}fake\n"
    end

    it 'uses requested partial'

    it 'uses view partials without controller' do
      PublicActivity.set_controller(nil)
      subject.render(self, two: 2)
      assert_equal rendered, "#{template_output}\n"
    end

    it 'provides local variables' do
      PublicActivity.set_controller(nil)
      subject.render(self, locals: { two: 2 })
      assert_equal rendered.chomp, '2'
    end

    it 'uses translations only when requested' do
      I18n.config.backend.store_translations(:en, activity: { test: '%{one} %{two}' })
      subject.render(self, two: 2, display: :i18n)
      assert_equal rendered, '1 2'
    end

    it 'pass all params to view context' do
      view_context = mock('ViewContext')
      PublicActivity.set_controller(nil)
      view_context.expects(:render).with { |params| params[:formats] == ['json'] }
      subject.render(view_context, formats: ['json'])
    end

    it 'uses specified layout' do
      PublicActivity.set_controller(nil)
      subject.render(self, layout: 'activity')
      assert_includes rendered, 'Here be the layouts'

      subject.render(self, layout: 'layouts/activity')
      assert_includes rendered, 'Here be the layouts'

      subject.render(self, layout: :activity)
      assert_includes rendered, 'Here be the layouts'
    end

    it 'accepts a custom layout root' do
      subject.render(self, layout: :layout, layout_root: 'custom')
      assert_includes rendered, 'Here be the custom layouts'
    end

    it 'accepts an absolute layout path' do
      subject.render(self, layout: '/custom/layout')
      assert_includes rendered, 'Here be the custom layouts'
    end

    it 'accepts a template root' do
      subject.render(self, root: 'custom')
      assert_includes rendered, 'Custom Template Root'
    end
  end
end


================================================
FILE: test/test_common.rb
================================================
# frozen_string_literal: true

require 'test_helper'

describe PublicActivity::Common do
  before do
    @owner     = User.create(name: 'Peter Pan')
    @recipient = User.create(name: 'Bruce Wayne')
    @options   = {
      params: {
        author_name: 'Peter',
        summary: 'Default summary goes here...'
      },
      owner: @owner,
      recipient: @recipient
    }
  end
  subject { article(@options).new }

  it 'prioritizes parameters passed to #create_activity' do
    subject.save
    assert_equal subject.create_activity(:test, params: { author_name: 'Pan' }).parameters[:author_name], 'Pan'
    assert_equal subject.create_activity(:test, parameters: { author_name: 'Pan' }).parameters[:author_name], 'Pan'
    assert_nil subject.create_activity(:test, params: { author_name: nil }).parameters[:author_name]
    assert_nil subject.create_activity(:test, parameters: { author_name: nil }).parameters[:author_name]
  end

  it 'prioritizes owner passed to #create_activity' do
    subject.save
    assert_equal subject.create_activity(:test, owner: @recipient).owner, @recipient
    assert_nil subject.create_activity(:test, owner: nil).owner
  end

  it 'prioritizes recipient passed to #create_activity' do
    subject.save
    assert_equal subject.create_activity(:test, recipient: @owner).recipient, @owner
    assert_nil subject.create_activity(:test, recipient: nil).recipient
  end

  it 'uses global fields' do
    subject.save
    activity = subject.activities.last
    assert_equal activity.parameters, @options[:params]
    assert_equal activity.owner, @owner
  end

  it 'allows custom fields' do
    subject.save
    subject.create_activity :with_custom_fields, nonstandard: 'Custom allowed'
    assert_equal subject.activities.last.nonstandard, 'Custom allowed'
  end

  it '#create_activity returns a new activity object' do
    subject.save
    assert subject.create_activity('some.key')
  end

  it '#create_activity! returns a new activity object' do
    subject.save
    activity = subject.create_activity!('some.key')
    assert activity.persisted?
    assert_equal 'article.some.key', activity.key
  end

  it 'update action should not create activity on save unless model changed' do
    subject.save
    before_count = subject.activities.count
    subject.save
    subject.save
    after_count = subject.activities.count
    assert_equal before_count, after_count
  end

  it 'allows passing owner through #create_activity' do
    article = article().new
    article.save
    activity = article.create_activity('some.key', owner: @owner)
    assert_equal activity.owner, @owner
  end

  it 'allows resolving custom fields' do
    subject.name      = 'Resolving is great'
    subject.published = true
    subject.save
    subject.create_activity :with_custom_fields, nonstandard: :name
    assert_equal subject.activities.last.nonstandard, 'Resolving is great'
    subject.create_activity :with_custom_fields_2, nonstandard: proc { |_, model| model.published.to_s }
    assert_equal subject.activities.last.nonstandard, 'true'
  end

  it 'inherits instance parameters' do
    subject.activity params: { author_name: 'Michael' }
    subject.save
    activity = subject.activities.last

    assert_equal activity.parameters[:author_name], 'Michael'
  end

  it 'accepts instance recipient' do
    subject.activity recipient: @recipient
    subject.save
    assert_equal subject.activities.last.recipient, @recipient
  end

  it 'accepts instance owner' do
    subject.activity owner: @owner
    subject.save
    assert_equal subject.activities.last.owner, @owner
  end

  it 'accepts owner as a symbol' do
    klass = article(owner: :user)
    @article = klass.new(user: @owner)
    @article.save
    activity = @article.activities.last

    assert_equal activity.owner, @owner
  end

  it 'reports PublicActivity::Activity as the base class' do
    if ENV['PA_ORM'] == 'active_record' # Only relevant for ActiveRecord
      subject.save
      assert_equal subject.activities.last.class.base_class, PublicActivity::Activity
    end
  end

  describe '#prepare_key' do
    describe 'for class#activity_key method' do
      before do
        @article = article(owner: :user).new(user: @owner)
      end

      it 'assigns key to value of activity_key if set' do
        def @article.activity_key; 'my_custom_key' end

        assert_equal @article.prepare_key(:create, {}), 'my_custom_key'
      end

      it 'assigns key based on class name as fallback' do
        def @article.activity_key; nil end

        assert_equal @article.prepare_key(:create), 'article.create'
      end

      it 'assigns key value from options hash' do
        assert_equal @article.prepare_key(:create, key: :my_custom_key), 'my_custom_key'
      end
    end

    describe 'for camel cased classes' do
      before do
        class CamelCase < article(owner: :user)
          def self.name; 'CamelCase' end
        end
        @camel_case = CamelCase.new
      end

      it 'assigns generates key from class name' do
        assert_equal @camel_case.prepare_key(:create, {}), 'camel_case.create'
      end
    end

    describe 'for namespaced classes' do
      before do
        module ::MyNamespace;
          class CamelCase < article(owner: :user)
            def self.name; 'MyNamespace::CamelCase' end
          end
        end
        @namespaced_camel_case = MyNamespace::CamelCase.new
      end

      it 'assigns key value from options hash' do
        assert_equal @namespaced_camel_case.prepare_key(:create, {}), 'my_namespace_camel_case.create'
      end
    end
  end

  # no key implicated or given
  specify do
    assert_raises(PublicActivity::NoKeyProvided) { subject.prepare_settings }
  end

  describe 'resolving values' do
    it 'allows procs with models and controllers' do
      context = mock('context')
      context.expects(:accessor).times(2).returns(5)
      controller = mock('controller')
      controller.expects(:current_user).returns(:cu)
      PublicActivity.set_controller(controller)
      p = proc { |c, m|
        assert_equal :cu, c.current_user
        assert_equal 5, m.accessor
      }
      PublicActivity.resolve_value(context, p)
      PublicActivity.resolve_value(context, :accessor)
    end
  end

  def teardown
    PublicActivity.set_controller(nil)
  end
end


================================================
FILE: test/test_controller_integration.rb
================================================
# frozen_string_literal: true

require 'test_helper'

class StoringController < ActionView::TestCase::TestController
  include PublicActivity::StoreController
  include ActionController::Testing
end

describe PublicActivity::StoreController do
  it 'stores controller' do
    controller = StoringController.new
    PublicActivity.set_controller(controller)
    assert_same controller, Thread.current[:public_activity_controller]
    assert_same controller, PublicActivity.get_controller
  end

  it 'stores controller with a filter in controller' do
    controller = StoringController.new

    callbacks = controller._process_action_callbacks.select { |c| c.kind == :around }.map(&:filter)
    assert_includes(callbacks, :store_controller_for_public_activity)

    public_activity_controller =
      controller.instance_eval do
        store_controller_for_public_activity do
          PublicActivity.get_controller
        end
      end

    assert_equal controller, public_activity_controller
  end

  it 'stores controller in a threadsafe way' do
    PublicActivity.set_controller(1)
    assert_equal PublicActivity.get_controller, 1

    Thread.new do
      PublicActivity.set_controller(2)
      assert_equal 2, PublicActivity.get_controller
      PublicActivity.set_controller(nil)
    end

    assert_equal PublicActivity.get_controller, 1

    PublicActivity.set_controller(nil)
  end
end


================================================
FILE: test/test_generators.rb
================================================
# frozen_string_literal: true

if ENV['PA_ORM'] == 'active_record'

  require 'test_helper'
  require 'rails/generators/test_case'
  require 'generators/public_activity/migration/migration_generator'
  require 'generators/public_activity/migration_upgrade/migration_upgrade_generator'

  class TestMigrationGenerator < Rails::Generators::TestCase
    tests PublicActivity::Generators::MigrationGenerator
    destination File.expand_path('../tmp', File.dirname(__FILE__))
    setup :prepare_destination

    def test_generating_activity_model
      run_generator
      assert_migration 'db/migrate/create_activities.rb'
    end
  end

  class TestMigrationUpgradeGenerator < Rails::Generators::TestCase
    tests PublicActivity::Generators::MigrationUpgradeGenerator
    destination File.expand_path('../tmp', File.dirname(__FILE__))
    setup :prepare_destination

    def test_generating_activity_model
      run_generator
      assert_migration 'db/migrate/upgrade_activities.rb'
    end
  end
end


================================================
FILE: test/test_helper.rb
================================================
# frozen_string_literal: true

require 'rubygems'
require 'bundler'
require 'logger'
Bundler.setup(:default, :test)

if ENV['COV']
  require 'simplecov'
  SimpleCov.start do
    add_filter '/test/'
  end
end
$:.unshift File.expand_path('../lib', __dir__)
require 'active_support/testing/setup_and_teardown'
require 'public_activity'
require 'public_activity/testing'
require 'pry'
require 'minitest/autorun'
require 'mocha/minitest'

PublicActivity::Config.orm = (ENV['PA_ORM'] || :active_record)

case PublicActivity::Config.orm
when :active_record
  require 'active_record'
  require 'active_record/connection_adapters/sqlite3_adapter'
  require 'stringio'        # silence the output
  $stdout = StringIO.new    # from migrator
  ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')

  migrations_path = File.expand_path('migrations', __dir__)
  active_record_version = ActiveRecord.version.release

  if active_record_version >= Gem::Version.new('7.2.0')
    migration_context = ActiveRecord::MigrationContext.new(migrations_path)
    migrations = migration_context.migrations   # => Array<ActiveRecord::MigrationProxy>
    connection_pool = ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
    schema_migration = ActiveRecord::SchemaMigration.new(connection_pool)
    internal_metadata = ActiveRecord::InternalMetadata.new(connection_pool)

    ActiveRecord::Migrator.new(
      :up,
      migrations,
      schema_migration,
      internal_metadata
    ).migrate
  else
    ActiveRecord::MigrationContext.new(migrations_path, ActiveRecord::SchemaMigration).migrate
  end

  $stdout = STDOUT

  def article(options = {})
    Class.new(ActiveRecord::Base) do
      self.table_name = 'articles'
      include PublicActivity::Model
      tracked options
      belongs_to :user

      def self.name
        'Article'
      end
    end
  end

  class User < ActiveRecord::Base; end
when :mongoid
  require 'mongoid'

  Mongoid.load!(File.expand_path('test/mongoid.yml'), :test)

  class User
    include Mongoid::Document
    include Mongoid::Timestamps

    has_many :articles

    field :name, type: String
  end

  class Article
    include Mongoid::Document
    include Mongoid::Timestamps
    include PublicActivity::Model

    if ::Mongoid::VERSION.split('.')[0].to_i >= 7
      belongs_to :user, optional: true
    else
      belongs_to :user
    end

    field :name, type: String
    field :published, type: Boolean
  end

  def article(options = {})
    Article.class_eval do
      set_public_activity_class_defaults
      tracked options
    end
    Article
  end
when :mongo_mapper
  require 'mongo_mapper'

  config = YAML.safe_load(File.read('test/mongo_mapper.yml'), aliases: true)
  MongoMapper.setup(config, :test)

  class User
    include MongoMapper::Document

    has_many :articles

    key :name, String
    timestamps!
  end

  class Article
    include MongoMapper::Document
    include PublicActivity::Model

    belongs_to :user

    key :name, String
    key :published, Boolean
  end

  def article(options = {})
    Article.class_eval do
      set_public_activity_class_defaults
      tracked options
    end
    Article
  end
end

class ViewSpec < Minitest::Spec
  prepend ActiveSupport::Testing::SetupAndTeardown
  include ActionView::TestCase::Behavior
end
Minitest::Spec.register_spec_type(/Rendering$/, ViewSpec)


================================================
FILE: test/test_testing.rb
================================================
# frozen_string_literal: true

require 'test_helper'

describe PublicActivity do
  describe 'self.with_tracking' do
    after do
      PublicActivity.enabled = true
    end

    it 'enables tracking inside the block' do
      PublicActivity.enabled = false

      PublicActivity.with_tracking do
        assert PublicActivity.enabled?
      end
    end

    it 'restores previous `enabled` state' do
      PublicActivity.enabled = false
      PublicActivity.with_tracking do
        # something
      end

      assert_equal PublicActivity.enabled?, false
    end
  end

  describe 'self.without_tracking' do
    it 'disables tracking inside the block' do
      PublicActivity.enabled = true

      PublicActivity.without_tracking do
        assert_equal PublicActivity.enabled?, false
      end
    end
  end
end


================================================
FILE: test/test_tracking.rb
================================================
# frozen_string_literal: true

require 'test_helper'

describe PublicActivity::Tracked do
  describe 'defining instance options' do
    subject { article.new }
    let :options do
      {
        key: 'key',
        params: { a: 1 },
        owner: User.create,
        recipient: User.create
      }
    end
    before(:each) { subject.activity(options) }
    let(:activity) { subject.save; subject.activities.last }

    specify { assert_same subject.activity_key, options[:key] }
    specify { assert_equal activity.key, options[:key] }

    specify { assert_same subject.activity_owner, options[:owner] }
    specify { assert_equal activity.owner, options[:owner] }

    specify { assert_same subject.activity_params, options[:params] }
    specify { assert_equal activity.parameters, options[:params] }

    specify { assert_same subject.activity_recipient, options[:recipient] }
    specify { assert_equal activity.recipient, options[:recipient] }
  end

  it 'can be tracked and be an activist at the same time' do
    case PublicActivity.config.orm
    when :mongoid
      class ActivistAndTrackedArticle
        include Mongoid::Document
        include Mongoid::Timestamps
        include PublicActivity::Model

        if ::Mongoid::VERSION.split('.')[0].to_i >= 7
          belongs_to :user, optional: true
        else
          belongs_to :user
        end

        field :name, type: String
        field :published, type: Boolean
        tracked
        activist
      end
    when :mongo_mapper
      class ActivistAndTrackedArticle
        include MongoMapper::Document
        include PublicActivity::Model

        belongs_to :user

        key :name, String
        key :published, Boolean
        tracked
        activist
        timestamps!
      end
    when :active_record
      class ActivistAndTrackedArticle < ActiveRecord::Base
        self.table_name = 'articles'
        include PublicActivity::Model
        tracked
        activist

        belongs_to :user
      end
    end

    art = ActivistAndTrackedArticle.new
    art.save
    assert_equal art.activities.last.trackable_id, art.id
    assert_nil art.activities.last.owner_id
  end

  describe 'custom fields' do
    describe 'global' do
      it 'should resolve symbols' do
        a = article(nonstandard: :name).new(name: 'Symbol resolved')
        a.save
        assert_equal a.activities.last.nonstandard, 'Symbol resolved'
      end

      it 'should resolve procs' do
        a = article(nonstandard: proc { |_, model| model.name }).new(name: 'Proc resolved')
        a.save
        assert_equal a.activities.last.nonstandard, 'Proc resolved'
      end
    end

    describe 'instance' do
      it 'should resolve symbols' do
        a = article.new(name: 'Symbol resolved')
        a.activity nonstandard: :name
        a.save
        assert_equal a.activities.last.nonstandard, 'Symbol resolved'
      end

      it 'should resolve procs' do
        a = article.new(name: 'Proc resolved')
        a.activity nonstandard: proc { |_, model| model.name }
        a.save
        assert_equal a.activities.last.nonstandard, 'Proc resolved'
      end
    end
  end

  it 'should reset instance options on successful create_activity' do
    a = article.new
    a.activity key: 'test', params: { test: 1 }
    a.save
    assert_equal a.activities.count, 1
    assert_raises(PublicActivity::NoKeyProvided) { a.create_activity }
    assert_empty a.activity_params
    a.activity key: 'asd'
    a.create_activity
    assert_raises(PublicActivity::NoKeyProvided) { a.create_activity }
  end

  it 'should not accept global key option' do
    # this example tests the lack of presence of sth that should not be here
    a = article(key: 'asd').new
    a.save
    assert_raises(PublicActivity::NoKeyProvided) { a.create_activity }
    assert_equal a.activities.count, 1
  end

  it 'should not change global custom fields' do
    a = article(nonstandard: 'global').new
    a.activity nonstandard: 'instance'
    a.save
    assert_equal a.class.activity_custom_fields_global, nonstandard: 'global'
  end

  describe 'disabling functionality' do
    it 'allows for global disable' do
      PublicActivity.enabled = false
      activity_count_before = PublicActivity::Activity.count

      @article = article.new
      @article.save
      assert_equal PublicActivity::Activity.count, activity_count_before

      PublicActivity.enabled = true
    end

    it 'allows for class-wide disable' do
      activity_count_before = PublicActivity::Activity.count

      klass = article
      klass.public_activity_off
      @article = klass.new
      @article.save
      assert_equal PublicActivity::Activity.count, activity_count_before

      klass.public_activity_on
      @article.name = 'Changed Article'
      @article.save
      assert(PublicActivity::Activity.count > activity_count_before)
    end
  end

  describe '#tracked' do
    subject { article(options) }
    let(:options) { {} }

    it 'allows skipping the tracking on CRUD actions' do
      art =
        case PublicActivity.config.orm
        when :mongoid
          Class.new do
            include Mongoid::Document
            include Mongoid::Timestamps
            include PublicActivity::Model

            belongs_to :user

            field :name, type: String
            field :published, type: Boolean
            tracked skip_defaults: true
          end
        when :mongo_mapper
          Class.new do
            include MongoMapper::Document
            include PublicActivity::Model

            belongs_to :user

            key :name, String
            key :published, Boolean
            tracked skip_defaults: true

            timestamps!
          end
        when :active_record
          article(skip_defaults: true)
        end

      assert_includes art, PublicActivity::Common
      refute_includes art, PublicActivity::Creation
      refute_includes art, PublicActivity::Update
      refute_includes art, PublicActivity::Destruction
    end

    describe 'default options' do
      subject { article }

      specify { assert_includes subject, PublicActivity::Creation }
      specify { assert_includes subject, PublicActivity::Destruction }
      specify { assert_includes subject, PublicActivity::Update }

      specify do
        callbacks = subject._create_callbacks.select do |c|
          c.kind.eql?(:after) && c.filter == :activity_on_create
        end

        refute_empty callbacks
      end

      specify do
        callbacks = subject._update_callbacks.select do |c|
          c.kind.eql?(:after) && c.filter == :activity_on_update
        end

        refute_empty callbacks
      end

      specify do
        callbacks = subject._destroy_callbacks.select do |c|
          c.kind.eql?(:before) && c.filter == :activity_on_destroy
        end

        refute_empty callbacks
      end
    end

    it 'accepts :except option' do
      art =
        case PublicActivity.config.orm
        when :mongoid
          Class.new do
            include Mongoid::Document
            include Mongoid::Timestamps
            include PublicActivity::Model

            belongs_to :user

            field :name, type: String
            field :published, type: Boolean
            tracked except: [:create]
          end
        when :mongo_mapper
          Class.new do
            include MongoMapper::Document
            include PublicActivity::Model

            belongs_to :user

            key :name, String
            key :published, Boolean
            tracked except: [:create]

            timestamps!
          end
        when :active_record
          article(except: [:create])
        end

      refute_includes art, PublicActivity::Creation
      assert_includes art, PublicActivity::Update
      assert_includes art, PublicActivity::Destruction
    end

    it 'accepts :only option' do
      art =
        case PublicActivity.config.orm
        when :mongoid
          Class.new do
            include Mongoid::Document
            include Mongoid::Timestamps
            include PublicActivity::Model

            belongs_to :user

            field :name, type: String
            field :published, type: Boolean

            tracked only: %i[create update]
          end
        when :mongo_mapper
          Class.new do
            include MongoMapper::Document
            include PublicActivity::Model

            belongs_to :user

            key :name, String
            key :published, Boolean

            tracked only: %i[create update]
          end
        when :active_record
          article(only: %I[create update])
        end

      assert_includes art, PublicActivity::Creation
      refute_includes art, PublicActivity::Destruction
      assert_includes art, PublicActivity::Update
    end

    it 'accepts :owner option' do
      owner = mock('owner')
      subject.tracked(owner: owner)
      assert_equal subject.activity_owner_global, owner
    end

    it 'accepts :params option' do
      params = { a: 1 }
      subject.tracked(params: params)
      assert_equal subject.activity_params_global, params
    end

    it 'accepts :on option' do
      on = { a: -> {}, b: proc {} }
      subject.tracked(on: on)
      assert_equal subject.activity_hooks, on
    end

    it 'accepts :on option with string keys' do
      on = { 'a' => -> {} }
      subject.tracked(on: on)
      assert_equal subject.activity_hooks, on.symbolize_keys
    end

    it 'accepts :on values that are procs' do
      on = { unpassable: 1, proper: -> {}, proper_proc: proc {} }
      subject.tracked(on: on)
      assert_includes subject.activity_hooks, :proper
      assert_includes subject.activity_hooks, :proper_proc
      refute_includes subject.activity_hooks, :unpassable
    end

    describe 'global options' do
      subject { article(recipient: :test, owner: :test2, params: { a: 'b' }) }

      specify { assert_equal subject.activity_recipient_global, :test }
      specify { assert_equal subject.activity_owner_global, :test2 }
      specify { assert_equal subject.activity_params_global, a: 'b' }
    end
  end

  describe 'activity hooks' do
    subject do
      s = article
      s.activity_hooks = { test: hook }
      s
    end
    let(:hook) { -> {} }

    it 'retrieves hooks' do
      assert_same hook, subject.get_hook(:test)
    end

    it 'retrieves hooks by string keys' do
      assert_same hook, subject.get_hook('test')
    end

    it 'returns nil when no matching hook is present' do
      assert_same nil, subject.get_hook(:nonexistent)
    end

    it 'allows hooks to decide if activity should be created' do
      subject.tracked
      @article = subject.new(name: 'Some Name')
      PublicActivity.set_controller(mock('controller'))
      pf = proc { |model, controller|
        assert_same controller, PublicActivity.get_controller
        assert_equal model.name, 'Some Name'
        false
      }
      pt = proc { |model, controller|
        assert_same controller, PublicActivity.get_controller
        assert_equal model.name, 'Other Name'
        true # this will save the activity with *.update key
      }
      @article.class.activity_hooks = { create: pf, update: pt, destroy: pt }

      assert_empty @article.activities.to_a
      @article.save # create
      @article.name = 'Other Name'
      @article.save # update
      @article.destroy # destroy

      assert_equal @article.activities.count, 2
      assert_equal @article.activities.first.key, 'article.update'
    end
  end

  def teardown
    PublicActivity.set_controller(nil)
  end
end


================================================
FILE: test/test_view_helpers.rb
================================================
# frozen_string_literal: true

require 'test_helper'

describe 'ViewHelpers Rendering' do
  include PublicActivity::ViewHelpers

  # is this a proper test?
  it 'provides render_activity helper' do
    activity = mock('activity')
    activity.stubs(:is_a?).with(PublicActivity::Activity).returns(true)
    activity.expects(:render).with(self, {})
    render_activity(activity)
  end

  it 'handles multiple activities' do
    activity = mock('activity')
    activity.expects(:render).with(self, {})
    render_activities([activity])
  end

  it 'flushes content_for between partials renderes' do
    @view_flow = mock('view_flow')
    @view_flow.expects(:set).twice.with('name', ActiveSupport::SafeBuffer.new)

    single_content_for('name', 'content')
    assert_equal @name, 'name'
    assert_equal @content, 'content'
    single_content_for('name', 'content2')
    assert_equal @name, 'name'
    assert_equal @content, 'content2'
  end

  def content_for(name, content)
    @name = name
    @content = content
  end
end


================================================
FILE: test/views/custom/_layout.erb
================================================
<h2>Here be the custom layouts</h2><%= yield %>


================================================
FILE: test/views/custom/_test.erb
================================================
Custom Template Root <%= activity.id %>


================================================
FILE: test/views/layouts/_activity.erb
================================================
<h2>Here be the layouts</h2><%= yield %>

================================================
FILE: test/views/public_activity/_test.erb
================================================
<% if defined?(two) == 'local-variable' %>
<% # output local_variable if defined %>
<%= two %>
<% else %>
<strong><%= p[:one] %>, <%= params['two'] %></strong>
<em><%= a.key %>, <%= activity.id %></em>
<%= current_user %>
<% end %>
Download .txt
gitextract_a19chaa2/

├── .editorconfig
├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── .travis.yml
├── Appraisals
├── CHANGELOG.md
├── Gemfile
├── MIT-LICENSE
├── README.md
├── Rakefile
├── gemfiles/
│   ├── .bundle/
│   │   └── config
│   ├── rails_6.1.gemfile
│   ├── rails_7.0.gemfile
│   └── rails_7.1.gemfile
├── lib/
│   ├── generators/
│   │   ├── public_activity/
│   │   │   ├── migration/
│   │   │   │   ├── migration_generator.rb
│   │   │   │   └── templates/
│   │   │   │       └── migration.rb
│   │   │   └── migration_upgrade/
│   │   │       ├── migration_upgrade_generator.rb
│   │   │       └── templates/
│   │   │           └── upgrade.rb
│   │   └── public_activity.rb
│   ├── public_activity/
│   │   ├── actions/
│   │   │   ├── creation.rb
│   │   │   ├── destruction.rb
│   │   │   └── update.rb
│   │   ├── activity.rb
│   │   ├── common.rb
│   │   ├── config.rb
│   │   ├── models/
│   │   │   ├── activist.rb
│   │   │   ├── activity.rb
│   │   │   ├── adapter.rb
│   │   │   └── trackable.rb
│   │   ├── orm/
│   │   │   ├── active_record/
│   │   │   │   ├── activist.rb
│   │   │   │   ├── activity.rb
│   │   │   │   ├── adapter.rb
│   │   │   │   └── trackable.rb
│   │   │   ├── active_record.rb
│   │   │   ├── mongo_mapper/
│   │   │   │   ├── activist.rb
│   │   │   │   ├── activity.rb
│   │   │   │   ├── adapter.rb
│   │   │   │   └── trackable.rb
│   │   │   ├── mongo_mapper.rb
│   │   │   ├── mongoid/
│   │   │   │   ├── activist.rb
│   │   │   │   ├── activity.rb
│   │   │   │   ├── adapter.rb
│   │   │   │   └── trackable.rb
│   │   │   └── mongoid.rb
│   │   ├── renderable.rb
│   │   ├── roles/
│   │   │   ├── deactivatable.rb
│   │   │   └── tracked.rb
│   │   ├── testing.rb
│   │   ├── utility/
│   │   │   ├── store_controller.rb
│   │   │   └── view_helpers.rb
│   │   └── version.rb
│   └── public_activity.rb
├── public_activity.gemspec
├── public_activity.sublime-project
└── test/
    ├── migrations/
    │   ├── 002_create_articles.rb
    │   ├── 003_create_users.rb
    │   └── 004_add_nonstandard_to_activities.rb
    ├── mongo_mapper.yml
    ├── mongoid.yml
    ├── test_activist.rb
    ├── test_activity.rb
    ├── test_common.rb
    ├── test_controller_integration.rb
    ├── test_generators.rb
    ├── test_helper.rb
    ├── test_testing.rb
    ├── test_tracking.rb
    ├── test_view_helpers.rb
    └── views/
        ├── custom/
        │   ├── _layout.erb
        │   └── _test.erb
        ├── layouts/
        │   └── _activity.erb
        └── public_activity/
            └── _test.erb
Download .txt
SYMBOL INDEX (217 symbols across 45 files)

FILE: lib/generators/public_activity.rb
  type PublicActivity (line 5) | module PublicActivity
    type Generators (line 7) | module Generators
      type Base (line 9) | module Base
        function source_root (line 11) | def source_root

FILE: lib/generators/public_activity/migration/migration_generator.rb
  type PublicActivity (line 6) | module PublicActivity
    type Generators (line 7) | module Generators
      class MigrationGenerator (line 9) | class MigrationGenerator < ActiveRecord::Generators::Base
        method generate_files (line 14) | def generate_files

FILE: lib/generators/public_activity/migration/templates/migration.rb
  class CreateActivities (line 4) | class CreateActivities < ActiveRecord::Migration[6.1]
    method up (line 5) | def self.up
    method down (line 18) | def self.down

FILE: lib/generators/public_activity/migration_upgrade/migration_upgrade_generator.rb
  type PublicActivity (line 6) | module PublicActivity
    type Generators (line 7) | module Generators
      class MigrationUpgradeGenerator (line 9) | class MigrationUpgradeGenerator < ActiveRecord::Generators::Base
        method generate_files (line 14) | def generate_files

FILE: lib/generators/public_activity/migration_upgrade/templates/upgrade.rb
  class UpgradeActivities (line 4) | class UpgradeActivities < ActiveRecord::Migration[5.0]
    method change (line 6) | def self.change

FILE: lib/public_activity.rb
  type PublicActivity (line 11) | module PublicActivity
    function enabled= (line 32) | def self.enabled=(value)
    function enabled? (line 40) | def self.enabled?
    function config (line 46) | def self.config
    function inherit_orm (line 52) | def self.inherit_orm(model = 'Activity')
    type Model (line 59) | module Model

FILE: lib/public_activity/actions/creation.rb
  type PublicActivity (line 3) | module PublicActivity
    type Creation (line 5) | module Creation
      function activity_on_create (line 15) | def activity_on_create

FILE: lib/public_activity/actions/destruction.rb
  type PublicActivity (line 3) | module PublicActivity
    type Destruction (line 5) | module Destruction
      function activity_on_destroy (line 15) | def activity_on_destroy

FILE: lib/public_activity/actions/update.rb
  type PublicActivity (line 3) | module PublicActivity
    type Update (line 5) | module Update
      function activity_on_update (line 15) | def activity_on_update

FILE: lib/public_activity/activity.rb
  type PublicActivity (line 3) | module PublicActivity
    class Activity (line 6) | class Activity < inherit_orm("Activity")

FILE: lib/public_activity/common.rb
  type PublicActivity (line 3) | module PublicActivity
    class NoKeyProvided (line 5) | class NoKeyProvided < Exception; end
    function resolve_value (line 11) | def self.resolve_value(context, thing)
    type Common (line 23) | module Common
      function set_public_activity_class_defaults (line 130) | def set_public_activity_class_defaults
      function get_hook (line 148) | def get_hook(key)
      function public_activity_enabled? (line 161) | def public_activity_enabled?
      function get_hook (line 170) | def get_hook(key)
      function call_hook_safe (line 181) | def call_hook_safe(key)
      function create_activity (line 248) | def create_activity(*args)
      function create_activity! (line 265) | def create_activity!(*args)
      function prepare_settings (line 287) | def prepare_settings(*args)
      function prepare_custom_fields (line 307) | def prepare_custom_fields(options)
      function prepare_parameters (line 319) | def prepare_parameters(options)
      function prepare_relation (line 330) | def prepare_relation(name, options)
      function prepare_key (line 343) | def prepare_key(action, options = {})
      function reset_activity_instance_options (line 355) | def reset_activity_instance_options

FILE: lib/public_activity/config.rb
  type PublicActivity (line 5) | module PublicActivity
    class Config (line 7) | class Config
      method set (line 17) | def self.set(&block)
      method orm= (line 28) | def self.orm=(orm = nil)
      method enabled= (line 34) | def self.enabled=(value = nil)
      method orm (line 40) | def orm(orm = nil)
      method table_name (line 46) | def table_name(name = nil)
      method enabled (line 52) | def enabled(value = nil)
      method orm (line 57) | def self.orm(orm = nil)
      method table_name (line 65) | def self.table_name(name = nil)
      method enabled (line 73) | def self.enabled(value = nil)
      class Block (line 83) | class Block
        method orm (line 85) | def orm(orm = nil)
        method enabled (line 91) | def enabled(value = nil)
        method table_name (line 96) | def table_name(name = nil)

FILE: lib/public_activity/models/activist.rb
  type PublicActivity (line 3) | module PublicActivity
    type Activist (line 5) | module Activist
      function included (line 7) | def self.included(base)

FILE: lib/public_activity/models/activity.rb
  type PublicActivity (line 3) | module PublicActivity
    class Activity (line 4) | class Activity < inherit_orm

FILE: lib/public_activity/models/adapter.rb
  type PublicActivity (line 3) | module PublicActivity
    class Adapter (line 5) | class Adapter < inherit_orm('Adapter')

FILE: lib/public_activity/models/trackable.rb
  type PublicActivity (line 3) | module PublicActivity
    type Trackable (line 5) | module Trackable
      function included (line 7) | def self.included(base)

FILE: lib/public_activity/orm/active_record/activist.rb
  type PublicActivity (line 3) | module PublicActivity
    type ORM (line 4) | module ORM
      type ActiveRecord (line 5) | module ActiveRecord
        type Activist (line 7) | module Activist
          function activist (line 25) | def activist

FILE: lib/public_activity/orm/active_record/activity.rb
  type PublicActivity (line 3) | module PublicActivity
    type ::PG (line 5) | module ::PG
      class ConnectionBad (line 6) | class ConnectionBad < Exception; end
    type Mysql2 (line 10) | module Mysql2
      type Error (line 11) | module Error
        class ConnectionError (line 12) | class ConnectionError < Exception; end
    type ORM (line 17) | module ORM
      type ActiveRecord (line 18) | module ActiveRecord
        class Activity (line 21) | class Activity < ::ActiveRecord::Base

FILE: lib/public_activity/orm/active_record/adapter.rb
  type PublicActivity (line 3) | module PublicActivity
    type ORM (line 4) | module ORM
      type ActiveRecord (line 7) | module ActiveRecord
        class Adapter (line 10) | class Adapter
          method create_activity (line 12) | def self.create_activity(trackable, options)
          method create_activity! (line 17) | def self.create_activity!(trackable, options)

FILE: lib/public_activity/orm/active_record/trackable.rb
  type PublicActivity (line 3) | module PublicActivity
    type ORM (line 4) | module ORM
      type ActiveRecord (line 5) | module ActiveRecord
        type Trackable (line 8) | module Trackable
          function extended (line 11) | def self.extended(base)

FILE: lib/public_activity/orm/mongo_mapper/activist.rb
  type PublicActivity (line 3) | module PublicActivity
    type ORM (line 4) | module ORM
      type MongoMapper (line 5) | module MongoMapper
        type Activist (line 7) | module Activist
          function activist (line 25) | def activist

FILE: lib/public_activity/orm/mongo_mapper/activity.rb
  type PublicActivity (line 6) | module PublicActivity
    type ORM (line 7) | module ORM
      type MongoMapper (line 8) | module MongoMapper
        class Activity (line 11) | class Activity
          class SymbolHash (line 15) | class SymbolHash < Hash
            method from_mongo (line 16) | def self.from_mongo(value)

FILE: lib/public_activity/orm/mongo_mapper/adapter.rb
  type PublicActivity (line 3) | module PublicActivity
    type ORM (line 4) | module ORM
      type MongoMapper (line 5) | module MongoMapper
        class Adapter (line 6) | class Adapter
          method create_activity (line 8) | def self.create_activity(trackable, options)
          method create_activity! (line 13) | def self.create_activity!(trackable, options)

FILE: lib/public_activity/orm/mongo_mapper/trackable.rb
  type PublicActivity (line 3) | module PublicActivity
    type ORM (line 4) | module ORM
      type MongoMapper (line 5) | module MongoMapper
        type Trackable (line 6) | module Trackable
          function extended (line 7) | def self.extended(base)

FILE: lib/public_activity/orm/mongoid/activist.rb
  type PublicActivity (line 3) | module PublicActivity
    type ORM (line 4) | module ORM
      type Mongoid (line 5) | module Mongoid
        type Activist (line 7) | module Activist
          function activist (line 24) | def activist

FILE: lib/public_activity/orm/mongoid/activity.rb
  type PublicActivity (line 5) | module PublicActivity
    type ORM (line 6) | module ORM
      type Mongoid (line 7) | module Mongoid
        class Activity (line 10) | class Activity

FILE: lib/public_activity/orm/mongoid/adapter.rb
  type PublicActivity (line 3) | module PublicActivity
    type ORM (line 4) | module ORM
      type Mongoid (line 5) | module Mongoid
        class Adapter (line 6) | class Adapter
          method create_activity (line 8) | def self.create_activity(trackable, options)
          method create_activity! (line 13) | def self.create_activity!(trackable, options)

FILE: lib/public_activity/orm/mongoid/trackable.rb
  type PublicActivity (line 3) | module PublicActivity
    type ORM (line 4) | module ORM
      type Mongoid (line 5) | module Mongoid
        type Trackable (line 6) | module Trackable
          function extended (line 7) | def self.extended(base)

FILE: lib/public_activity/renderable.rb
  type PublicActivity (line 3) | module PublicActivity
    type Renderable (line 6) | module Renderable
      function text (line 9) | def text(params = {})
      function render (line 99) | def render(context, params = {})
      function prepare_partial (line 122) | def prepare_partial(root, path)
      function prepare_locals (line 126) | def prepare_locals(params)
      function prepare_layout (line 143) | def prepare_layout(root, layout)
      function prepare_parameters (line 153) | def prepare_parameters(params)
      function template_path (line 164) | def template_path(key, partial_root)

FILE: lib/public_activity/roles/deactivatable.rb
  type PublicActivity (line 3) | module PublicActivity
    type Deactivatable (line 5) | module Deactivatable
      function public_activity_enabled? (line 19) | def public_activity_enabled?
      type ClassMethods (line 25) | module ClassMethods
        function public_activity_off (line 27) | def public_activity_off
        function public_activity_on (line 32) | def public_activity_on
        function set_public_activity_class_defaults (line 38) | def set_public_activity_class_defaults

FILE: lib/public_activity/roles/tracked.rb
  type PublicActivity (line 3) | module PublicActivity
    type Tracked (line 5) | module Tracked
      function activity (line 32) | def activity(options = {})
      function tracked (line 135) | def tracked(opts = {})
      function include_default_actions (line 147) | def include_default_actions(options)
      function available_options (line 167) | def available_options
      function assign_globals (line 171) | def assign_globals(options)
      function assign_hooks (line 179) | def assign_hooks(options)
      function assign_custom_fields (line 185) | def assign_custom_fields(options)

FILE: lib/public_activity/testing.rb
  type PublicActivity (line 9) | module PublicActivity
    function with_tracking (line 16) | def self.with_tracking
    function without_tracking (line 30) | def self.without_tracking

FILE: lib/public_activity/utility/store_controller.rb
  type PublicActivity (line 3) | module PublicActivity
    function set_controller (line 6) | def set_controller(controller)
    function get_controller (line 11) | def get_controller
    type StoreController (line 17) | module StoreController
      function store_controller_for_public_activity (line 25) | def store_controller_for_public_activity

FILE: lib/public_activity/utility/view_helpers.rb
  type PublicActivity (line 4) | module PublicActivity
    type ViewHelpers (line 6) | module ViewHelpers
      function render_activity (line 8) | def render_activity activities, options = {}
      function single_content_for (line 21) | def single_content_for(name, content = nil, &block)

FILE: lib/public_activity/version.rb
  type PublicActivity (line 3) | module PublicActivity

FILE: test/migrations/002_create_articles.rb
  class CreateArticles (line 3) | class CreateArticles < ActiveRecord::Migration[6.1]
    method up (line 4) | def self.up

FILE: test/migrations/003_create_users.rb
  class CreateUsers (line 3) | class CreateUsers < ActiveRecord::Migration[6.1]
    method up (line 4) | def self.up

FILE: test/migrations/004_add_nonstandard_to_activities.rb
  class AddNonstandardToActivities (line 3) | class AddNonstandardToActivities < ActiveRecord::Migration[6.1]
    method change (line 4) | def change

FILE: test/test_activist.rb
  class ActivistUser (line 31) | class ActivistUser < ActiveRecord::Base
  class ActivistUser (line 37) | class ActivistUser
  class ActivistUser (line 45) | class ActivistUser

FILE: test/test_common.rb
  function activity_key (line 134) | def @article.activity_key; 'my_custom_key' end
  function activity_key (line 140) | def @article.activity_key; nil end
  class CamelCase (line 152) | class CamelCase < article(owner: :user)
    method name (line 153) | def self.name; 'CamelCase' end
  type ::MyNamespace (line 165) | module ::MyNamespace;
    class CamelCase (line 166) | class CamelCase < article(owner: :user)
      method name (line 167) | def self.name; 'MyNamespace::CamelCase' end
  function teardown (line 200) | def teardown

FILE: test/test_controller_integration.rb
  class StoringController (line 5) | class StoringController < ActionView::TestCase::TestController

FILE: test/test_generators.rb
  class TestMigrationGenerator (line 10) | class TestMigrationGenerator < Rails::Generators::TestCase
    method test_generating_activity_model (line 15) | def test_generating_activity_model
  class TestMigrationUpgradeGenerator (line 21) | class TestMigrationUpgradeGenerator < Rails::Generators::TestCase
    method test_generating_activity_model (line 26) | def test_generating_activity_model

FILE: test/test_helper.rb
  function article (line 54) | def article(options = {})
  class User (line 67) | class User < ActiveRecord::Base; end
  class User (line 73) | class User
  class Article (line 82) | class Article
  function article (line 97) | def article(options = {})
  class User (line 110) | class User
  class Article (line 119) | class Article
  function article (line 129) | def article(options = {})
  class ViewSpec (line 138) | class ViewSpec < Minitest::Spec

FILE: test/test_tracking.rb
  class ActivistAndTrackedArticle (line 35) | class ActivistAndTrackedArticle
  class ActivistAndTrackedArticle (line 52) | class ActivistAndTrackedArticle
  class ActivistAndTrackedArticle (line 65) | class ActivistAndTrackedArticle < ActiveRecord::Base
  function teardown (line 404) | def teardown

FILE: test/test_view_helpers.rb
  function content_for (line 34) | def content_for(name, content)
Condensed preview — 72 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (110K chars).
[
  {
    "path": ".editorconfig",
    "chars": 227,
    "preview": "root = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ni"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 899,
    "preview": "name: CI\non:\n  pull_request:\n    paths-ignore:\n      - 'README.md'\n  push:\n    paths-ignore:\n      - 'README.md'\n  workf"
  },
  {
    "path": ".gitignore",
    "chars": 89,
    "preview": "/doc/\n/.yardoc/\n*.gem\n/coverage/\n/*.sublime-workspace\n/tmp\n/Gemfile.lock\n/gemfiles/*.lock"
  },
  {
    "path": ".travis.yml",
    "chars": 631,
    "preview": "language: ruby\nrvm:\n  - 2.2.6\n  - 2.3.3\nmatrix:\n  include:\n    - rvm: 2.2.6\n      gemfile: gemfiles/Gemfile.rails-4.0\n  "
  },
  {
    "path": "Appraisals",
    "chars": 250,
    "preview": "# frozen_string_literal: true\n\nif RUBY_VERSION.to_f < 3.1\n  appraise 'rails_6.1' do\n    gem 'rails', '~> 6.1.0'\n    gem "
  },
  {
    "path": "CHANGELOG.md",
    "chars": 5538,
    "preview": "# Changelog\n\n## 3.0.2\n\n- **Fixed** Refactor prepare_parameters method to handle nil parameters (s. #387, thanks [Himalay"
  },
  {
    "path": "Gemfile",
    "chars": 69,
    "preview": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\ngemspec\n"
  },
  {
    "path": "MIT-LICENSE",
    "chars": 1064,
    "preview": "Copyright (c) 2011-2013 Piotrek Okoński\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of"
  },
  {
    "path": "README.md",
    "chars": 8447,
    "preview": "# PublicActivity [![Code Climate](https://codeclimate.com/github/chaps-io/public_activity.svg)](https://codeclimate.com/"
  },
  {
    "path": "Rakefile",
    "chars": 392,
    "preview": "# frozen_string_literal: true\n\nrequire 'bundler/gem_tasks'\nrequire 'rake'\nrequire 'yard'\nrequire 'yard/rake/yardoc_task'"
  },
  {
    "path": "gemfiles/.bundle/config",
    "chars": 22,
    "preview": "---\nBUNDLE_RETRY: \"1\"\n"
  },
  {
    "path": "gemfiles/rails_6.1.gemfile",
    "chars": 130,
    "preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"rails\", \"~> 6.1.0\"\ngem \"openssl\"\n\ngemspec pa"
  },
  {
    "path": "gemfiles/rails_7.0.gemfile",
    "chars": 116,
    "preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"rails\", \"~> 7.0.1\"\n\ngemspec path: \"../\"\n"
  },
  {
    "path": "gemfiles/rails_7.1.gemfile",
    "chars": 116,
    "preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"rails\", \"~> 7.1.0\"\n\ngemspec path: \"../\"\n"
  },
  {
    "path": "lib/generators/public_activity/migration/migration_generator.rb",
    "chars": 538,
    "preview": "# frozen_string_literal: true\n\nrequire 'generators/public_activity'\nrequire 'rails/generators/active_record'\n\nmodule Pub"
  },
  {
    "path": "lib/generators/public_activity/migration/templates/migration.rb",
    "chars": 487,
    "preview": "# frozen_string_literal: true\n\n# Migration responsible for creating a table with activities\nclass CreateActivities < Act"
  },
  {
    "path": "lib/generators/public_activity/migration_upgrade/migration_upgrade_generator.rb",
    "chars": 544,
    "preview": "# frozen_string_literal: true\n\nrequire 'generators/public_activity'\nrequire 'rails/generators/active_record'\n\nmodule Pub"
  },
  {
    "path": "lib/generators/public_activity/migration_upgrade/templates/upgrade.rb",
    "chars": 288,
    "preview": "# frozen_string_literal: true\n\n# Migration responsible for creating a table with activities\nclass UpgradeActivities < Ac"
  },
  {
    "path": "lib/generators/public_activity.rb",
    "chars": 420,
    "preview": "# frozen_string_literal: true\n\nrequire 'rails/generators/named_base'\n\nmodule PublicActivity\n  # A generator module with "
  },
  {
    "path": "lib/public_activity/actions/creation.rb",
    "chars": 398,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  # Handles creation of Activities upon destruction and update of t"
  },
  {
    "path": "lib/public_activity/actions/destruction.rb",
    "chars": 401,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  # Handles creation of Activities upon destruction of tracked mode"
  },
  {
    "path": "lib/public_activity/actions/update.rb",
    "chars": 551,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  # Handles creation of Activities upon destruction and update of t"
  },
  {
    "path": "lib/public_activity/activity.rb",
    "chars": 209,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  # Main model, stores all information about what happened,\n  # who"
  },
  {
    "path": "lib/public_activity/common.rb",
    "chars": 12360,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  # Happens when creating custom activities without either action o"
  },
  {
    "path": "lib/public_activity/config.rb",
    "chars": 2425,
    "preview": "# frozen_string_literal: true\n\nrequire 'singleton'\n\nmodule PublicActivity\n  # Class used to initialize configuration obj"
  },
  {
    "path": "lib/public_activity/models/activist.rb",
    "chars": 275,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  # Provides helper methods for selecting activities from a user.\n "
  },
  {
    "path": "lib/public_activity/models/activity.rb",
    "chars": 94,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  class Activity < inherit_orm\n  end\nend\n"
  },
  {
    "path": "lib/public_activity/models/adapter.rb",
    "chars": 168,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  # Loads database-specific routines for use by PublicActivity.\n  c"
  },
  {
    "path": "lib/public_activity/models/trackable.rb",
    "chars": 277,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  # Provides association for activities bound to this object by *tr"
  },
  {
    "path": "lib/public_activity/orm/active_record/activist.rb",
    "chars": 1082,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  module ORM\n    module ActiveRecord\n      # Module extending class"
  },
  {
    "path": "lib/public_activity/orm/active_record/activity.rb",
    "chars": 1968,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  unless defined? ::PG::ConnectionBad\n    module ::PG\n      class C"
  },
  {
    "path": "lib/public_activity/orm/active_record/adapter.rb",
    "chars": 716,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  module ORM\n    # Support for ActiveRecord for PublicActivity. Use"
  },
  {
    "path": "lib/public_activity/orm/active_record/trackable.rb",
    "chars": 526,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  module ORM\n    module ActiveRecord\n      # Implements {PublicActi"
  },
  {
    "path": "lib/public_activity/orm/active_record.rb",
    "chars": 223,
    "preview": "# frozen_string_literal: true\n\nrequire 'active_record'\nrequire_relative 'active_record/activity'\nrequire_relative 'activ"
  },
  {
    "path": "lib/public_activity/orm/mongo_mapper/activist.rb",
    "chars": 1023,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  module ORM\n    module MongoMapper\n      # Module extending classe"
  },
  {
    "path": "lib/public_activity/orm/mongo_mapper/activity.rb",
    "chars": 931,
    "preview": "# frozen_string_literal: true\n\nrequire 'mongo_mapper'\nrequire 'active_support/core_ext'\n\nmodule PublicActivity\n  module "
  },
  {
    "path": "lib/public_activity/orm/mongo_mapper/adapter.rb",
    "chars": 516,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  module ORM\n    module MongoMapper\n      class Adapter\n        # C"
  },
  {
    "path": "lib/public_activity/orm/mongo_mapper/trackable.rb",
    "chars": 304,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  module ORM\n    module MongoMapper\n      module Trackable\n        "
  },
  {
    "path": "lib/public_activity/orm/mongo_mapper.rb",
    "chars": 207,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"mongo_mapper/activity.rb\"\nrequire_relative \"mongo_mapper/adapter.rb\"\nre"
  },
  {
    "path": "lib/public_activity/orm/mongoid/activist.rb",
    "chars": 1022,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  module ORM\n    module Mongoid\n      # Module extending classes th"
  },
  {
    "path": "lib/public_activity/orm/mongoid/activity.rb",
    "chars": 991,
    "preview": "# frozen_string_literal: true\n\nrequire 'mongoid'\n\nmodule PublicActivity\n  module ORM\n    module Mongoid\n      # The Acti"
  },
  {
    "path": "lib/public_activity/orm/mongoid/adapter.rb",
    "chars": 512,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  module ORM\n    module Mongoid\n      class Adapter\n        # Creat"
  },
  {
    "path": "lib/public_activity/orm/mongoid/trackable.rb",
    "chars": 280,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  module ORM\n    module Mongoid\n      module Trackable\n        def "
  },
  {
    "path": "lib/public_activity/orm/mongoid.rb",
    "chars": 187,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"mongoid/activity.rb\"\nrequire_relative \"mongoid/adapter.rb\"\nrequire_rela"
  },
  {
    "path": "lib/public_activity/renderable.rb",
    "chars": 6159,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  # Provides logic for rendering activities. Handles both i18n stri"
  },
  {
    "path": "lib/public_activity/roles/deactivatable.rb",
    "chars": 1197,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  # Enables per-class disabling of PublicActivity functionality.\n  "
  },
  {
    "path": "lib/public_activity/roles/tracked.rb",
    "chars": 7573,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  # Main module extending classes we want to keep track of.\n  modul"
  },
  {
    "path": "lib/public_activity/testing.rb",
    "chars": 976,
    "preview": "# frozen_string_literal: true\n\n# This file provides functionality for testing your code with public_activity\n# activated"
  },
  {
    "path": "lib/public_activity/utility/store_controller.rb",
    "chars": 882,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  class << self\n    # Setter for remembering controller instance\n  "
  },
  {
    "path": "lib/public_activity/utility/view_helpers.rb",
    "chars": 1120,
    "preview": "# frozen_string_literal: true\n\n# Provides a shortcut from views to the rendering method.\nmodule PublicActivity\n  # Modul"
  },
  {
    "path": "lib/public_activity/version.rb",
    "chars": 77,
    "preview": "# frozen_string_literal: true\n\nmodule PublicActivity\n  VERSION = '3.0.2'\nend\n"
  },
  {
    "path": "lib/public_activity.rb",
    "chars": 2218,
    "preview": "# frozen_string_literal: true\n\nrequire 'active_support'\nrequire 'logger'\nrequire 'action_view'\n# +public_activity+ keeps"
  },
  {
    "path": "public_activity.gemspec",
    "chars": 2323,
    "preview": "# frozen_string_literal: true\n\n$LOAD_PATH.push File.expand_path('../lib', __FILE__)\nrequire 'public_activity/version'\n\nG"
  },
  {
    "path": "public_activity.sublime-project",
    "chars": 477,
    "preview": "{\n  \"folders\":\n  [\n    {\n      \"path\": \"./\",\n      \"folder_exclude_patterns\": [\"coverage\", \".yardoc\", \"doc\"]\n    }\n  ],\n"
  },
  {
    "path": "test/migrations/002_create_articles.rb",
    "chars": 241,
    "preview": "# frozen_string_literal: true\n\nclass CreateArticles < ActiveRecord::Migration[6.1]\n  def self.up\n    create_table :artic"
  },
  {
    "path": "test/migrations/003_create_users.rb",
    "chars": 183,
    "preview": "# frozen_string_literal: true\n\nclass CreateUsers < ActiveRecord::Migration[6.1]\n  def self.up\n    create_table :users do"
  },
  {
    "path": "test/migrations/004_add_nonstandard_to_activities.rb",
    "chars": 190,
    "preview": "# frozen_string_literal: true\n\nclass AddNonstandardToActivities < ActiveRecord::Migration[6.1]\n  def change\n    change_t"
  },
  {
    "path": "test/mongo_mapper.yml",
    "chars": 70,
    "preview": "test:\n  host: 127.0.0.1\n  port: 27017\n  database: public_activity_test"
  },
  {
    "path": "test/mongoid.yml",
    "chars": 106,
    "preview": "test:\n  clients:\n    default:\n      hosts:\n        - 127.0.0.1:27017\n      database: public_activity_test\n"
  },
  {
    "path": "test/test_activist.rb",
    "chars": 1688,
    "preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\ndescribe PublicActivity::Activist do\n  it 'adds owner association'"
  },
  {
    "path": "test/test_activity.rb",
    "chars": 2806,
    "preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\ndescribe 'PublicActivity::Activity Rendering' do\n  describe '#text"
  },
  {
    "path": "test/test_common.rb",
    "chars": 6327,
    "preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\ndescribe PublicActivity::Common do\n  before do\n    @owner     = Us"
  },
  {
    "path": "test/test_controller_integration.rb",
    "chars": 1397,
    "preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass StoringController < ActionView::TestCase::TestController\n  i"
  },
  {
    "path": "test/test_generators.rb",
    "chars": 1000,
    "preview": "# frozen_string_literal: true\n\nif ENV['PA_ORM'] == 'active_record'\n\n  require 'test_helper'\n  require 'rails/generators/"
  },
  {
    "path": "test/test_helper.rb",
    "chars": 3389,
    "preview": "# frozen_string_literal: true\n\nrequire 'rubygems'\nrequire 'bundler'\nrequire 'logger'\nBundler.setup(:default, :test)\n\nif "
  },
  {
    "path": "test/test_testing.rb",
    "chars": 814,
    "preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\ndescribe PublicActivity do\n  describe 'self.with_tracking' do\n    "
  },
  {
    "path": "test/test_tracking.rb",
    "chars": 11600,
    "preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\ndescribe PublicActivity::Tracked do\n  describe 'defining instance "
  },
  {
    "path": "test/test_view_helpers.rb",
    "chars": 1023,
    "preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\ndescribe 'ViewHelpers Rendering' do\n  include PublicActivity::View"
  },
  {
    "path": "test/views/custom/_layout.erb",
    "chars": 48,
    "preview": "<h2>Here be the custom layouts</h2><%= yield %>\n"
  },
  {
    "path": "test/views/custom/_test.erb",
    "chars": 40,
    "preview": "Custom Template Root <%= activity.id %>\n"
  },
  {
    "path": "test/views/layouts/_activity.erb",
    "chars": 40,
    "preview": "<h2>Here be the layouts</h2><%= yield %>"
  },
  {
    "path": "test/views/public_activity/_test.erb",
    "chars": 232,
    "preview": "<% if defined?(two) == 'local-variable' %>\n<% # output local_variable if defined %>\n<%= two %>\n<% else %>\n<strong><%= p["
  }
]

About this extraction

This page contains the full source code of the pokonski/public_activity GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 72 files (99.7 KB), approximately 26.7k tokens, and a symbol index with 217 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!