tag_echidna 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ spec/internal/db/*.sqlite
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,6 @@
1
+ class TagEchidna::Tag < ActiveRecord::Base
2
+ has_many :taggings, :class_name => 'TagEchidna::Tagging',
3
+ :dependent => :destroy
4
+
5
+ validates :name, :presence => true, :uniqueness => true
6
+ end
@@ -0,0 +1,7 @@
1
+ class TagEchidna::Tagging < ActiveRecord::Base
2
+ belongs_to :taggable, :polymorphic => true
3
+ belongs_to :tag, :class_name => 'TagEchidna::Tag'
4
+
5
+ validates :taggable, :presence => true
6
+ validates :tag, :presence => true
7
+ end
@@ -0,0 +1,27 @@
1
+ class TagTables < ActiveRecord::Migration
2
+ def up
3
+ create_table :taggings do |t|
4
+ t.integer :tag_id, :null => false
5
+ t.integer :taggable_id, :null => false
6
+ t.string :taggable_type, :null => false
7
+ t.timestamps
8
+ end
9
+
10
+ add_index :taggings, :tag_id
11
+ add_index :taggings, [:taggable_type, :taggable_id]
12
+ add_index :taggings, [:taggable_type, :taggable_id, :tag_id],
13
+ :unique => true, :name => 'unique_taggings'
14
+
15
+ create_table :tags do |t|
16
+ t.string :name, :null => false
17
+ t.timestamps
18
+ end
19
+
20
+ add_index :tags, :name, :unique => true
21
+ end
22
+
23
+ def down
24
+ drop_table :tags
25
+ drop_table :taggings
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ module TagEchidna
2
+ #
3
+ end
4
+
5
+ require 'tag_echidna/active_record'
6
+ require 'tag_echidna/engine'
7
+ require 'tag_echidna/tag_names'
@@ -0,0 +1,26 @@
1
+ module TagEchidna::ActiveRecord
2
+ def self.included(base)
3
+ base.extend TagEchidna::ActiveRecord::ClassMethods
4
+ end
5
+
6
+ module ClassMethods
7
+ def has_many_tags
8
+ has_many :taggings, :class_name => 'TagEchidna::Tagging',
9
+ :as => :taggable, :dependent => :destroy
10
+ has_many :tags, :class_name => 'TagEchidna::Tag',
11
+ :through => :taggings
12
+ end
13
+ end
14
+
15
+ def tag_names
16
+ @tag_names ||= TagEchidna::TagNames.new self
17
+ end
18
+
19
+ def tag_names=(names)
20
+ if names.is_a?(TagEchidna::TagNames)
21
+ @tag_names = names
22
+ else
23
+ @tag_names = TagEchidna::TagNames.new_with_names self, names
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ require 'rails/engine'
2
+
3
+ class TagEchidna::Engine < Rails::Engine
4
+ engine_name :tag_echidna
5
+
6
+ ActiveSupport.on_load :active_record do
7
+ include TagEchidna::ActiveRecord
8
+ end
9
+ end
@@ -0,0 +1,51 @@
1
+ class TagEchidna::TagNames
2
+ include Enumerable
3
+
4
+ def self.new_with_names(taggable, names)
5
+ tag_names = new(taggable)
6
+ tag_names.clear
7
+ names.each { |name| tag_names << name }
8
+ tag_names
9
+ end
10
+
11
+ def initialize(taggable)
12
+ @taggable = taggable
13
+ end
14
+
15
+ def to_a
16
+ taggable.tags.collect &:name
17
+ end
18
+
19
+ def +(array)
20
+ array.each { |name| self.<< name }
21
+ self
22
+ end
23
+
24
+ def -(array)
25
+ array.each { |name| self.delete name }
26
+ self
27
+ end
28
+
29
+ def <<(name)
30
+ tag = TagEchidna::Tag.where(:name => name).first ||
31
+ TagEchidna::Tag.create(:name => name)
32
+
33
+ taggable.tags << tag
34
+ end
35
+
36
+ def clear
37
+ taggable.tags.clear
38
+ end
39
+
40
+ def delete(name)
41
+ taggable.tags.delete TagEchidna::Tag.where(:name => name).first
42
+ end
43
+
44
+ def each(&block)
45
+ to_a.each &block
46
+ end
47
+
48
+ private
49
+
50
+ attr_reader :taggable
51
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Managing tags via names" do
4
+ let(:article) { Article.create }
5
+
6
+ it "returns tag names" do
7
+ article.tags << TagEchidna::Tag.create(:name => 'melbourne')
8
+
9
+ article.tag_names.to_a.should == ['melbourne']
10
+ end
11
+
12
+ it "adds tags via their names" do
13
+ article.tag_names << 'melbourne'
14
+
15
+ article.tags.collect(&:name).should == ['melbourne']
16
+ end
17
+
18
+ it "accepts a completely new set of tags" do
19
+ article.tag_names = ['portland', 'oregon']
20
+
21
+ article.tags.collect(&:name).should == ['portland', 'oregon']
22
+ end
23
+
24
+ it "enumerates through tag names" do
25
+ article.tag_names = ['melbourne', 'victoria']
26
+ names = []
27
+
28
+ article.tag_names.each do |name|
29
+ names << name
30
+ end
31
+
32
+ names.should == ['melbourne', 'victoria']
33
+ end
34
+
35
+ it "does not allow duplication of tags" do
36
+ existing = Article.create
37
+ existing.tags << TagEchidna::Tag.create(:name => 'portland')
38
+
39
+ article.tag_names = ['portland']
40
+
41
+ existing.tag_ids.should == article.tag_ids
42
+ end
43
+
44
+ it "appends tag names" do
45
+ article.tag_names = ['portland']
46
+ article.tag_names += ['oregon', 'ruby']
47
+
48
+ article.tags.collect(&:name).should == ['portland', 'oregon', 'ruby']
49
+ end
50
+
51
+ it "removes a single tag name" do
52
+ article.tag_names = ['portland', 'oregon']
53
+ article.tag_names.delete 'oregon'
54
+
55
+ article.tags.collect(&:name).should == ['portland']
56
+ end
57
+
58
+ it "removes tag names" do
59
+ article.tag_names = ['portland', 'oregon', 'ruby']
60
+ article.tag_names -= ['oregon', 'ruby']
61
+
62
+ article.tags.collect(&:name).should == ['portland']
63
+ end
64
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Adding and removing tags' do
4
+ let(:article) { Article.create }
5
+ let(:pancakes) { TagEchidna::Tag.create :name => 'pancakes' }
6
+
7
+ it "stores new tags" do
8
+ article.tags << pancakes
9
+
10
+ article.tags.reload.should == [pancakes]
11
+ end
12
+
13
+ it "removes existing tags" do
14
+ article.tags << pancakes
15
+
16
+ article.tags.delete pancakes
17
+
18
+ article.tags.reload.should == []
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ class Article < ActiveRecord::Base
2
+ has_many_tags
3
+ end
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: db/combustion_test.sqlite
@@ -0,0 +1,6 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table :articles, :force => true do |t|
3
+ t.string :title
4
+ t.timestamps
5
+ end
6
+ end
@@ -0,0 +1 @@
1
+ *.log
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+
3
+ Bundler.require :default, :development
4
+
5
+ Combustion.initialize! :active_record
6
+
7
+ require 'rspec/rails'
8
+
9
+ RSpec.configure do |config|
10
+ config.use_transactional_fixtures = true
11
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ Gem::Specification.new do |s|
3
+ s.name = 'tag_echidna'
4
+ s.version = '0.1.0'
5
+ s.authors = ['Pat Allan']
6
+ s.email = ['pat@freelancing-gods.com']
7
+ s.homepage = 'https://github.com/pat/tag_echidna'
8
+ s.summary = 'The Tag Echidna'
9
+ s.description = 'This friendly echidna gives you tags in your Rails app.'
10
+
11
+ s.files = `git ls-files`.split("\n")
12
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
13
+ s.require_paths = ['lib']
14
+
15
+ s.add_runtime_dependency 'activerecord', '>= 3.2.0'
16
+ s.add_development_dependency 'combustion', '~> 0.4.0'
17
+ s.add_development_dependency 'rspec-rails', '~> 2.13'
18
+ s.add_development_dependency 'sqlite3', '~> 1.3.7'
19
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tag_echidna
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Pat Allan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: combustion
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.4.0
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.4.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec-rails
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.13'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.13'
62
+ - !ruby/object:Gem::Dependency
63
+ name: sqlite3
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 1.3.7
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 1.3.7
78
+ description: This friendly echidna gives you tags in your Rails app.
79
+ email:
80
+ - pat@freelancing-gods.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - Gemfile
87
+ - app/models/tag_echidna/tag.rb
88
+ - app/models/tag_echidna/tagging.rb
89
+ - db/migrate/1_tag_tables.rb
90
+ - lib/tag_echidna.rb
91
+ - lib/tag_echidna/active_record.rb
92
+ - lib/tag_echidna/engine.rb
93
+ - lib/tag_echidna/tag_names.rb
94
+ - spec/acceptance/tag_names_spec.rb
95
+ - spec/acceptance/tags_spec.rb
96
+ - spec/internal/app/models/article.rb
97
+ - spec/internal/config/database.yml
98
+ - spec/internal/db/schema.rb
99
+ - spec/internal/log/.gitignore
100
+ - spec/spec_helper.rb
101
+ - tag_echidna.gemspec
102
+ homepage: https://github.com/pat/tag_echidna
103
+ licenses: []
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 1.8.23
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: The Tag Echidna
126
+ test_files: []
127
+ has_rdoc: