lean_tag 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d5cf556a9c2a9df241b42def112546eae8296a4c
4
+ data.tar.gz: 7d543b45c7596ec547f85715f340a21da152d353
5
+ SHA512:
6
+ metadata.gz: c357fffbd13651a7cde6121681f3a936faff15ac155a25e6522da539278c8908892208ceb32da8e78de6cf2d72a48706cacbe99852befdd7a73f6afeac9b5148
7
+ data.tar.gz: 7a2fed477fb443be8e657cb652c831487b5812034f086ddb79cdc2a66ce4e78198e547412337a08aa1e5c8fbd9112c3438e9ec9ce47075ef1121a351236e251a
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ Bundler::GemHelper.install_tasks
8
+
9
+ require 'rspec/core/rake_task'
10
+ RSpec::Core::RakeTask.new do |t|
11
+ t.pattern = 'spec/**/*_spec.rb'
12
+ end
13
+
14
+ task default: :spec
@@ -0,0 +1,9 @@
1
+ class CreateTags < ActiveRecord::Migration
2
+ def change
3
+ create_table :tags do |t|
4
+ t.string :name, null: false, index: true
5
+ t.integer :taggings_count, null: false, default: 0
6
+ t.timestamps null: false
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ class CreateTaggings < ActiveRecord::Migration
2
+ def change
3
+ create_table :taggings do |t|
4
+ t.references :tag, index: true
5
+ t.references :record, polymorphic: true, index: true
6
+
7
+ t.timestamps null: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ require 'rails/engine'
2
+
3
+ require 'lean_tag/tag'
4
+ require 'lean_tag/taggable'
5
+ require 'lean_tag/tagging'
6
+
7
+ module LeanTag
8
+ class Engine < ::Rails::Engine
9
+
10
+ isolate_namespace LeanTag
11
+
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ module LeanTag
2
+ class Tag < ActiveRecord::Base
3
+
4
+ has_many :records, through: :taggings
5
+ has_many :taggings, class_name: "LeanTag::Tagging", inverse_of: :tag, counter_cache: true
6
+
7
+ scope :ranked, -> { order("taggings_count DESC") }
8
+
9
+ validates :name, presence: true, uniqueness: true
10
+
11
+ def name=(value)
12
+ self[:name] = value.present? ? value.gsub(/[^0-9a-zA-Z]+/, "").downcase : nil
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,116 @@
1
+ module LeanTag
2
+ module Taggable
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ has_many :taggings, class_name: "LeanTag::Tagging", as: :record, inverse_of: :record, dependent: :destroy
7
+ has_many :tags, through: :taggings
8
+
9
+ accepts_nested_attributes_for :taggings, allow_destroy: true
10
+
11
+ scope :with_tags, -> { includes(:tags) }
12
+ end
13
+ end
14
+
15
+ ##
16
+ # Adds a single tag on parent save
17
+ def add_tag(tag)
18
+ if tag.is_a?(String)
19
+ tag_name = tag
20
+ tag = Tag.find_by_name(tag_name)
21
+
22
+ if tag.nil?
23
+ self.tags.build(name: tag_name)
24
+ elsif !self.taggings.exists?(tag_id: tag.id)
25
+ self.taggings.build(tag_id: tag.id)
26
+ end
27
+ else
28
+ self.taggings.build(tag_id: tag.id)
29
+ end
30
+ end
31
+
32
+ ##
33
+ # Adds a single tag immediately
34
+ def add_tag!(tag)
35
+ if tag.is_a?(String)
36
+ tag_name = tag
37
+ tag = Tag.find_by_name(tag_name)
38
+
39
+ if tag.nil?
40
+ self.tags.create(name: tag_name)
41
+ elsif !self.taggings.exists?(tag_id: tag.id)
42
+ self.taggings.create(tag_id: tag.id)
43
+ end
44
+ else
45
+ self.taggings.create(tag_id: tag.id)
46
+ end
47
+ end
48
+
49
+ ##
50
+ # Destroy a tag if it's no longer in use
51
+ def destroy_if_unused(tag)
52
+ if tag.taggings_count && LeanTag.remove_unused
53
+ tag.destroy
54
+ end
55
+ end
56
+
57
+ ##
58
+ # Finds current tags on this record which aren't in the passed list
59
+ def excluded_tags(tag_names)
60
+ self.with_tags.tags.reject { |t| t.name.in?(tag_names) }
61
+ end
62
+
63
+ ##
64
+ # Finds a tag on this record by name
65
+ def find_tag(tag_name)
66
+ self.tags.find_by_name(tag_name)
67
+ end
68
+
69
+ ##
70
+ # Finds current tags on this record which are in the passed list
71
+ def included_tags(tag_names)
72
+ self.with_tags.tags.select { |t| t.name.in?(tag_names) }
73
+ end
74
+
75
+ ##
76
+ # Removes a single tag on parent save
77
+ def remove_tag(tag, method='mark_for_destruction')
78
+ tag = self.find_tag(tag) if tag.is_a?(String)
79
+
80
+ tagging = tagging.find_by_tag_id(tag.id)
81
+ tagging.send(method) unless tagging.nil?
82
+
83
+ destroy_if_unused(tag)
84
+ end
85
+
86
+ ##
87
+ # Removes a single tag immediately
88
+ def remove_tag!(tag)
89
+ tag = self.find_tag(tag) if tag.is_a?(String)
90
+
91
+ tagging = tagging.find_by_tag_id(tag.id)
92
+ tagging.destroy unless tagging.nil?
93
+
94
+ destroy_if_unused(tag)
95
+ end
96
+
97
+ ##
98
+ # Set a list of tags
99
+ def tag_list=(value)
100
+ tag_names = value.blank? ? [] : value.split(LeanTag.delimiter)
101
+
102
+ # Get rid of existing tags that aren't in the list
103
+ self.excluded_tags(tag_names).each { |t| self.remove_tag(t) }
104
+
105
+ # Add any new tags
106
+ tag_names.each { |t| self.add_tag(t) }
107
+ end
108
+
109
+ ##
110
+ # Returns a delimited list of tag names
111
+ def tag_list
112
+ self.tags.map(&:name).join(LeanTag.delimiter)
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,12 @@
1
+ module LeanTag
2
+ class Tagging < ActiveRecord::Base
3
+
4
+ belongs_to :record, polymorphic: true, inverse_of: :taggings
5
+ belongs_to :tag, class_name: "LeanTag::Tag", inverse_of: :taggings
6
+
7
+ validates :record_id, presence: true
8
+ validates :record_type, presence: true
9
+ validates :tag, presence: true, uniqueness: { scope: [:record_type, :record_id] }
10
+
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module LeanTag
2
+
3
+ VERSION = '0.1.0'
4
+
5
+ end
data/lib/lean_tag.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'active_record'
2
+ require 'active_record/version'
3
+ require 'active_support/core_ext/module'
4
+
5
+ require_relative 'lean_tag/engine' if defined?(Rails)
6
+
7
+ module LeanTag
8
+
9
+ def self.setup
10
+ @configuration ||= Configuration.new
11
+ yield @configuration if block_given?
12
+ end
13
+
14
+ class Configuration
15
+
16
+ attr_accessor :delimiter, :force_lowercase, :force_parameterize
17
+
18
+ def initialize
19
+ self.delimiter = ','
20
+ self.force_lowercase = true
21
+ self.remove_unused = true
22
+ end
23
+
24
+ end
25
+
26
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lean_tag
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Matt Ellis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activerecord
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '4.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '4.0'
69
+ description: And simple and clean implementation of content tagging for Rails 4 and
70
+ above
71
+ email:
72
+ - m.ellis27@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - Rakefile
78
+ - db/migrate/1_create_tags.rb
79
+ - db/migrate/2_create_taggings.rb
80
+ - lib/lean_tag.rb
81
+ - lib/lean_tag/engine.rb
82
+ - lib/lean_tag/tag.rb
83
+ - lib/lean_tag/taggable.rb
84
+ - lib/lean_tag/tagging.rb
85
+ - lib/lean_tag/version.rb
86
+ homepage: https://github.com/waffleau/lean_tag
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.4.4
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: A lightweight method for tagging content
110
+ test_files: []