pebbles-path 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pebbles-path.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Katrina Owen
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # PebblePath
2
+
3
+ Provides searchable, parseable pebbles-compliant UID paths, e.g. (such as `a.b.*`) for Active Record models.
4
+
5
+ ## Requirements
6
+
7
+ Requires ActiveModel. The target class (the one that will contain the `path` property) needs to have fields in the DB for:
8
+
9
+ ```
10
+ label_0
11
+ label_1
12
+ label_2
13
+ label_3
14
+ label_4
15
+ label_5
16
+ label_6
17
+ label_7
18
+ label_8
19
+ label_9
20
+ ```
21
+
22
+ ## Installation
23
+
24
+ Add this line to your application's Gemfile:
25
+
26
+ gem 'pebble_path'
27
+
28
+ And then execute:
29
+
30
+ $ bundle
31
+
32
+ Or install it yourself as:
33
+
34
+ $ gem install pebble_path
35
+
36
+ Create a migration for the table that you want to put the paths on, e.g.
37
+
38
+ def self.up
39
+ labels = (0..9).map { |i| "label_#{i}".to_sym }
40
+
41
+ create_table :locations do |t|
42
+ labels.each do |label|
43
+ t.text label
44
+ end
45
+ t.timestamps
46
+ end
47
+
48
+ add_index :locations, labels, :unique => true, :name => 'index_locations_on_labels'
49
+ end
50
+
51
+
52
+ ## Usage
53
+
54
+ Include the `PebblePath` module in the `ActiveRecord` model that has the labels
55
+
56
+ ```
57
+ class Location < ActiveRecord::Base
58
+ include PebblePath
59
+ end
60
+ ```
61
+
62
+ ## Contributing
63
+
64
+ 1. Fork it
65
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
66
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
67
+ 4. Push to the branch (`git push origin my-new-feature`)
68
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,61 @@
1
+ require "pebbles-path/version"
2
+
3
+ module Pebbles
4
+ module Path
5
+
6
+ def self.max_depth
7
+ Positions::MAX_DEPTH
8
+ end
9
+
10
+ def self.to_conditions(paths)
11
+ Positions.to_conditions(paths)
12
+ end
13
+
14
+ def self.included(base)
15
+ base.class_eval do
16
+ scope :by_path, lambda { |path|
17
+ where Positions.to_conditions(path)
18
+ }
19
+
20
+ validates_presence_of :label_0
21
+ validate :must_be_valid_uid_path
22
+
23
+ after_initialize :initialize_path
24
+
25
+ def self.declare!(path)
26
+ raise ArgumentError, "Path must be valid" unless Pebbles::Uid.valid_path?(path)
27
+ attributes = PebblePath.to_conditions(path)
28
+ path = self.where(attributes).first
29
+ path ||= self.create!(attributes)
30
+ end
31
+
32
+ end
33
+ end
34
+
35
+ attr_reader :path
36
+ def path=(positions)
37
+ @path = Positions.new(positions)
38
+
39
+ path.all.each_with_index do |value, i|
40
+ send(:"label_#{i}=", value)
41
+ end
42
+ path
43
+ end
44
+
45
+ def initialize_path
46
+ positions = []
47
+ [:label_0, :label_1, :label_2, :label_3, :label_4, :label_5, :label_6, :label_7, :label_8, :label_9].each do |attribute|
48
+ positions << send(attribute)
49
+ end
50
+ self.path = positions
51
+ end
52
+
53
+ def must_be_valid_uid_path
54
+ unless Pebbles::Uid.valid_path?(self.path.to_s)
55
+ errors.add(:base, "Location path '#{self.path.to_s}' is invalid.")
56
+ end
57
+ end
58
+
59
+ end
60
+ end
61
+
@@ -0,0 +1,61 @@
1
+ require 'pebbles-uid'
2
+
3
+ module Pebbles::Path
4
+ class Positions
5
+ include Enumerable
6
+
7
+ MAX_DEPTH = 10
8
+
9
+ attr_reader :labels, :all
10
+ def initialize(positions)
11
+ @all = resolve positions
12
+ @labels = all.compact
13
+ end
14
+
15
+ def each
16
+ labels.each {|label| yield label}
17
+ end
18
+
19
+ def [](index)
20
+ labels[index]
21
+ end
22
+
23
+ def []=(index, value)
24
+ labels[index] = value
25
+ end
26
+
27
+ def to_s
28
+ labels.join('.')
29
+ end
30
+
31
+ def resolve(positions)
32
+ positions = positions.split('.') if positions.is_a?(String)
33
+ positions = truncate_invalid(positions)
34
+ (0...MAX_DEPTH).map do |i|
35
+ positions[i]
36
+ end
37
+ end
38
+
39
+ def truncate_invalid(positions)
40
+ labels = []
41
+ (0...MAX_DEPTH).each do |i|
42
+ break if positions[i].nil?
43
+ labels << positions[i]
44
+ end
45
+ labels
46
+ end
47
+
48
+ class << self
49
+
50
+ def to_conditions(path)
51
+ unless Pebbles::Uid::Wildcard.valid?(path)
52
+ raise ArgumentError.new("Wildcards terminate the path. Invalid path: #{path}")
53
+ end
54
+
55
+ labels = Pebbles::Uid::Labels.new(path, :name => 'label', :max_depth => MAX_DEPTH, :stop => nil)
56
+ labels.to_hash
57
+ end
58
+ end
59
+ end
60
+
61
+ end
@@ -0,0 +1,5 @@
1
+ module Pebbles
2
+ module Path
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ require 'pebbles-path'
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pebbles-path/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "pebbles-path"
8
+ gem.version = Pebbles::Path::VERSION
9
+ gem.authors = ["Katrina Owen"]
10
+ gem.email = ["katrina.owen@gmail.com"]
11
+ gem.description = %q{Provide pebble-compliant paths for ActiveRecord models.}
12
+ gem.summary = %q{Provides searchable, parseable pebble-compliant UID paths, e.g. (such as a.b.*) for Active Record models.}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency 'rspec'
21
+ gem.add_dependency 'pebbles-uid', '>=0.0.6'
22
+ end
data/spec/path_spec.rb ADDED
@@ -0,0 +1,98 @@
1
+ require 'pebbles-path'
2
+
3
+ class Thing
4
+ def self.scope(*attrs)
5
+ end
6
+ def self.after_initialize(*attrs)
7
+ end
8
+ def self.validates_presence_of(*attrs)
9
+ end
10
+ def self.validate(*attrs)
11
+ end
12
+
13
+ (0..9).each do |i|
14
+ attr_accessor "label_#{i}".to_sym
15
+ end
16
+
17
+ include Pebbles::Path
18
+ end
19
+
20
+ describe Pebbles::Path do
21
+ subject do
22
+ thing = Thing.new
23
+ thing.path = "a.b.c.d.e"
24
+ thing
25
+ end
26
+
27
+ describe "path" do
28
+
29
+ it "accepts an array" do
30
+ subject.path = %w(a b c)
31
+ "#{subject.path}".should eq("a.b.c")
32
+ end
33
+
34
+ it "accepts a string" do
35
+ subject.path = "a.b.c"
36
+ "#{subject.path}".should eq("a.b.c")
37
+ end
38
+
39
+ it "doesn't do weird stuff" do
40
+ subject.path = [nil, 'a']
41
+ "#{subject.path}".should eq("")
42
+ end
43
+
44
+ specify { subject.path.map{|label| label + label}.should eq %w(aa bb cc dd ee) }
45
+
46
+ specify { subject.path[1].should eq('b') }
47
+
48
+ specify do
49
+ subject.path[2] = 'x'
50
+ "#{subject.path}".should eq("a.b.x.d.e")
51
+ end
52
+
53
+ its(:label_0) { should eq('a') }
54
+ its(:label_1) { should eq('b') }
55
+ its(:label_2) { should eq('c') }
56
+ its(:label_3) { should eq('d') }
57
+ its(:label_4) { should eq('e') }
58
+
59
+ [:label_5, :label_6, :label_7, :label_8, :label_9].each do |attribute|
60
+ it "hasn't filled #{attribute}" do
61
+ subject.send(attribute).should be_nil
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "overwrites labels" do
67
+ before(:each) do
68
+ subject.path = 'a.b.c'
69
+ end
70
+
71
+ its(:label_0) { should eq('a') }
72
+ its(:label_1) { should eq('b') }
73
+ its(:label_2) { should eq('c') }
74
+
75
+ [:label_3, :label_4, :label_5, :label_6, :label_7, :label_8, :label_9].each do |attribute|
76
+ it "overwrites #{attribute}" do
77
+ subject.send(attribute).should be_nil
78
+ end
79
+ end
80
+ end
81
+
82
+ it "initializes path from label" do
83
+ subject.path = []
84
+ subject.label_0 = 'a'
85
+ subject.label_1 = 'b'
86
+ subject.label_2 = 'c'
87
+ subject.path.to_s.should eq('')
88
+ subject.initialize_path
89
+ subject.path.to_s.should eq('a.b.c')
90
+ end
91
+
92
+ describe "no stray labels" do
93
+ it "stops setting labels when it reaches a nil" do
94
+ subject.path = ['a', 'b', nil, 'd']
95
+ subject.path.to_s.should eq('a.b')
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,45 @@
1
+ require 'pebbles-path/positions'
2
+
3
+ describe Pebbles::Path::Positions do
4
+ subject { Pebbles::Path::Positions }
5
+
6
+ let(:full_path) do
7
+ {
8
+ :label_0 => "a",
9
+ :label_1 => "b",
10
+ :label_2 => "c",
11
+ :label_3 => "d",
12
+ :label_4 => "e",
13
+ :label_5 => "f",
14
+ :label_6 => "g",
15
+ :label_7 => "h",
16
+ :label_8 => "i",
17
+ :label_9 => "j",
18
+ }
19
+ end
20
+
21
+ describe "#to_conditions" do
22
+
23
+ specify do
24
+ subject.to_conditions("a.b.c.d.e.f.g.h.i.j").should eq(full_path)
25
+ end
26
+
27
+ specify do
28
+ subject.to_conditions("a.b.c").should eq({:label_0=>"a", :label_1=>"b", :label_2=>"c", :label_3=>nil})
29
+ end
30
+
31
+ specify do
32
+ subject.to_conditions("a.b.*").should eq({:label_0=>"a", :label_1=>"b"})
33
+ end
34
+
35
+ specify do
36
+ subject.to_conditions("a.^b.c").should eq({:label_0=>"a", :label_1=>["b", nil], :label_2=>["c", nil], :label_3=>nil})
37
+ end
38
+
39
+ specify do
40
+ subject.to_conditions("a.b|c.d").should eq({:label_0=>"a", :label_1=>["b", "c"], :label_2=>"d", :label_3=>nil})
41
+ end
42
+
43
+ end
44
+
45
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pebbles-path
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Katrina Owen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70095621197620 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70095621197620
25
+ - !ruby/object:Gem::Dependency
26
+ name: pebbles-uid
27
+ requirement: &70095621196600 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 0.0.6
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70095621196600
36
+ description: Provide pebble-compliant paths for ActiveRecord models.
37
+ email:
38
+ - katrina.owen@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - LICENSE.txt
46
+ - README.md
47
+ - Rakefile
48
+ - lib/pebbles-path.rb
49
+ - lib/pebbles-path/positions.rb
50
+ - lib/pebbles-path/version.rb
51
+ - lib/pebbles/path.rb
52
+ - pebbles-path.gemspec
53
+ - spec/path_spec.rb
54
+ - spec/positions_spec.rb
55
+ homepage: ''
56
+ licenses: []
57
+ post_install_message:
58
+ rdoc_options: []
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubyforge_project:
75
+ rubygems_version: 1.8.15
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Provides searchable, parseable pebble-compliant UID paths, e.g. (such as
79
+ a.b.*) for Active Record models.
80
+ test_files:
81
+ - spec/path_spec.rb
82
+ - spec/positions_spec.rb