lean_tag 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []