tsundere 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +58 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +166 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/tsundere/array.rb +58 -0
- data/lib/tsundere/class_methods.rb +57 -0
- data/lib/tsundere/imouto.rb +23 -0
- data/lib/tsundere/instance_methods.rb +38 -0
- data/lib/tsundere.rb +12 -0
- data/spec/array_spec.rb +59 -0
- data/spec/class_methods_spec.rb +34 -0
- data/spec/instance_methods_spec.rb +70 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/tsundere_spec.rb +9 -0
- data/test/helper.rb +18 -0
- data/test/test_tsundere.rb +7 -0
- data/tsundere.gemspec +75 -0
- metadata +168 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "debugger"
|
10
|
+
gem 'rspec', '~> 2.12.0'
|
11
|
+
gem "shoulda", ">= 0"
|
12
|
+
gem "rdoc", "~> 3.12"
|
13
|
+
gem "bundler", "~> 1.2.3"
|
14
|
+
gem "jeweler", "~> 1.8.4"
|
15
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (3.2.9)
|
5
|
+
i18n (~> 0.6)
|
6
|
+
multi_json (~> 1.0)
|
7
|
+
bourne (1.1.2)
|
8
|
+
mocha (= 0.10.5)
|
9
|
+
columnize (0.3.6)
|
10
|
+
debugger (1.2.2)
|
11
|
+
columnize (>= 0.3.1)
|
12
|
+
debugger-linecache (~> 1.1.1)
|
13
|
+
debugger-ruby_core_source (~> 1.1.5)
|
14
|
+
debugger-linecache (1.1.2)
|
15
|
+
debugger-ruby_core_source (>= 1.1.1)
|
16
|
+
debugger-ruby_core_source (1.1.5)
|
17
|
+
diff-lcs (1.1.3)
|
18
|
+
git (1.2.5)
|
19
|
+
i18n (0.6.1)
|
20
|
+
jeweler (1.8.4)
|
21
|
+
bundler (~> 1.0)
|
22
|
+
git (>= 1.2.5)
|
23
|
+
rake
|
24
|
+
rdoc
|
25
|
+
json (1.7.5)
|
26
|
+
metaclass (0.0.1)
|
27
|
+
mocha (0.10.5)
|
28
|
+
metaclass (~> 0.0.1)
|
29
|
+
multi_json (1.5.0)
|
30
|
+
rake (10.0.2)
|
31
|
+
rdoc (3.12)
|
32
|
+
json (~> 1.4)
|
33
|
+
rspec (2.12.0)
|
34
|
+
rspec-core (~> 2.12.0)
|
35
|
+
rspec-expectations (~> 2.12.0)
|
36
|
+
rspec-mocks (~> 2.12.0)
|
37
|
+
rspec-core (2.12.1)
|
38
|
+
rspec-expectations (2.12.0)
|
39
|
+
diff-lcs (~> 1.1.3)
|
40
|
+
rspec-mocks (2.12.0)
|
41
|
+
shoulda (3.3.2)
|
42
|
+
shoulda-context (~> 1.0.1)
|
43
|
+
shoulda-matchers (~> 1.4.1)
|
44
|
+
shoulda-context (1.0.1)
|
45
|
+
shoulda-matchers (1.4.2)
|
46
|
+
activesupport (>= 3.0.0)
|
47
|
+
bourne (~> 1.1.2)
|
48
|
+
|
49
|
+
PLATFORMS
|
50
|
+
ruby
|
51
|
+
|
52
|
+
DEPENDENCIES
|
53
|
+
bundler (~> 1.2.3)
|
54
|
+
debugger
|
55
|
+
jeweler (~> 1.8.4)
|
56
|
+
rdoc (~> 3.12)
|
57
|
+
rspec (~> 2.12.0)
|
58
|
+
shoulda
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Thomas Chen
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
## ~tsun tsun
|
2
|
+
|
3
|
+
Provides an interface to allow objects to behave differently based upon who is accessing them.
|
4
|
+
Objects implementing the tsundere class exposes a tsundere_for method that creates a proxy
|
5
|
+
which filters out unwanted access smoothly.
|
6
|
+
|
7
|
+
Suppose you have the following:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
# Object
|
11
|
+
class SchoolGirl
|
12
|
+
def speak_with words
|
13
|
+
...
|
14
|
+
end
|
15
|
+
|
16
|
+
def watch_movie_with person
|
17
|
+
...
|
18
|
+
end
|
19
|
+
|
20
|
+
def bathe_with person
|
21
|
+
...
|
22
|
+
end
|
23
|
+
|
24
|
+
def be_naughty_with person, &block
|
25
|
+
yield person, &block
|
26
|
+
...
|
27
|
+
end
|
28
|
+
|
29
|
+
def ignore
|
30
|
+
...
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
...
|
35
|
+
|
36
|
+
# Usage
|
37
|
+
rikka = SchoolGirl.new :chuu2
|
38
|
+
if person.is_a? Friend
|
39
|
+
rikka.speak_with person.words
|
40
|
+
else
|
41
|
+
rikka.ignore person
|
42
|
+
end
|
43
|
+
if person.is_a? Friend and person.is_a? Neighbor and person.name =~ /dark flame master/i
|
44
|
+
rikka.speak_with person.words
|
45
|
+
rikka.bathe_with person
|
46
|
+
...
|
47
|
+
end
|
48
|
+
```
|
49
|
+
The annoying thing is that you need to constantly check for access levels,
|
50
|
+
which makes your code a mess and becomes easily broken with new updates.
|
51
|
+
The tsundere interface provides an access level interface to make thing easier:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
# Object
|
55
|
+
class SchoolGirl
|
56
|
+
include Tsundere
|
57
|
+
attr_tsundere :speak_with, :as => { :stranger => 1 }
|
58
|
+
attr_tsundere :watch_movie_with, :as => { :friend => 2 }
|
59
|
+
attr_tsundere :bathe_with, be_naughty_with :as => { :dark_flame_master => 3 }
|
60
|
+
def speak_with words
|
61
|
+
...
|
62
|
+
end
|
63
|
+
|
64
|
+
def watch_movie_with person
|
65
|
+
...
|
66
|
+
end
|
67
|
+
|
68
|
+
def bathe_with person
|
69
|
+
...
|
70
|
+
end
|
71
|
+
|
72
|
+
def be_naughty_with person, &block
|
73
|
+
yield person, &block
|
74
|
+
...
|
75
|
+
end
|
76
|
+
|
77
|
+
def ignore
|
78
|
+
...
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
...
|
83
|
+
|
84
|
+
# Usage
|
85
|
+
rikka = SchoolGirl.new :chuu2
|
86
|
+
# if person is a friend, these method will work, if not, this method returns
|
87
|
+
# a string saying "sorry, this doesn't work"
|
88
|
+
rikka.tsundere_for(person).speak_with person.words
|
89
|
+
rikka.tsundere_for(person).watch_movie_with person,
|
90
|
+
...
|
91
|
+
```
|
92
|
+
Install
|
93
|
+
=
|
94
|
+
```
|
95
|
+
gem install tsundere
|
96
|
+
```
|
97
|
+
|
98
|
+
Usage
|
99
|
+
=
|
100
|
+
1. step 1: include the tsundere module into your class
|
101
|
+
```ruby
|
102
|
+
class Something
|
103
|
+
include Tsundere
|
104
|
+
...
|
105
|
+
```
|
106
|
+
|
107
|
+
2. step 2: declare what methods you'd like to be accessible in one of 3 ways:
|
108
|
+
```ruby
|
109
|
+
class Something
|
110
|
+
include Tsundere
|
111
|
+
attr_tsundere :some_method, :another_method, :as => :admin
|
112
|
+
attr_tsundere :fourth_method, :as => :management
|
113
|
+
```
|
114
|
+
admins can access some_method and another_method
|
115
|
+
management can access fourth_method
|
116
|
+
|
117
|
+
--
|
118
|
+
```ruby
|
119
|
+
class Something
|
120
|
+
include Tsundere
|
121
|
+
attr_tsundere :some_method, :another_method, :third_method, :as => {:admin => 5}
|
122
|
+
attr_tsundere :fourth_method, :as => {:super_admin => 6}
|
123
|
+
```
|
124
|
+
declared this way, and super_admin can not only access fourth_method, but also all
|
125
|
+
the methods the regular admin can access
|
126
|
+
|
127
|
+
--
|
128
|
+
```ruby
|
129
|
+
class Something
|
130
|
+
include Tsundere
|
131
|
+
attr_tsundere :some_method, :another_method, :third_method, :as => 5
|
132
|
+
attr_tsundere :fourth_method, :as => 6
|
133
|
+
```
|
134
|
+
this is the same as the previous version, except no names are specified,
|
135
|
+
but tsundere_for(6) can access fourth_method as well as all the methods
|
136
|
+
that tsundere_for(5) can access
|
137
|
+
|
138
|
+
Notes
|
139
|
+
=
|
140
|
+
```ruby
|
141
|
+
tsundere_for(duck)
|
142
|
+
```
|
143
|
+
tsundere_for will work as long as duck is either a string, fixnum, symbol, integer, or float.
|
144
|
+
Alternatively, if duck exposes a rank or level method that results in a fixnum, string, symbol, float, etc.,
|
145
|
+
this method will still work.
|
146
|
+
If duck is a hash, it must expose the :rank or :level key in order to work
|
147
|
+
If duck is nil, no methods are exposed.
|
148
|
+
|
149
|
+
If you don't want to bother with access levels at some point in your application,
|
150
|
+
simple call your original object without tsundere_for
|
151
|
+
|
152
|
+
Contributing to tsundere
|
153
|
+
=
|
154
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
155
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
156
|
+
* Fork the project.
|
157
|
+
* Start a feature/bugfix branch.
|
158
|
+
* Commit and push until you are happy with your contribution.
|
159
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
160
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
161
|
+
|
162
|
+
Copyright
|
163
|
+
=
|
164
|
+
Copyright (c) 2012 Thomas Chen. See LICENSE.txt for
|
165
|
+
further details.
|
166
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "tsundere"
|
18
|
+
gem.homepage = "http://github.com/foxnewsnetwork/tsundere"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{object buffer for graceful managment of permission}
|
21
|
+
gem.description = %Q{Any given object can implement the tsundere interface. Once implemented, a tsundere object will behave differently based upon who is calling it.}
|
22
|
+
gem.email = "foxnewsnetwork@gmail.com"
|
23
|
+
gem.authors = ["Thomas Chen"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
# require 'rcov/rcovtask'
|
36
|
+
# Rcov::RcovTask.new do |test|
|
37
|
+
# test.libs << 'test'
|
38
|
+
# test.pattern = 'test/**/test_*.rb'
|
39
|
+
# test.verbose = true
|
40
|
+
# test.rcov_opts << '--exclude "gems/*"'
|
41
|
+
# end
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rdoc/task'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "tsundere #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
# Array extension
|
3
|
+
class Array
|
4
|
+
|
5
|
+
# binary_search_raw
|
6
|
+
# param1: should be comparable against elements in the array
|
7
|
+
# if not, provide a block which can be used to do equals
|
8
|
+
# returns the index with the target if possible, but will
|
9
|
+
# otherwise return the index of the element that is the smallest
|
10
|
+
# element larger than the target. It's raw because it does
|
11
|
+
# not check if the array is sorted or not
|
12
|
+
def binary_search_raw target, opts={}
|
13
|
+
right_flag = true
|
14
|
+
right_flag = false if opts[:left]
|
15
|
+
if block_given?
|
16
|
+
return p_bisearch_internal( 0, count-1, target, right_flag) do |a,b|
|
17
|
+
yield a,b
|
18
|
+
end # return
|
19
|
+
else
|
20
|
+
return p_bisearch_internal( 0, count-1, target, right_flag ) do |a,b|
|
21
|
+
a <=> b
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end # binary_search
|
25
|
+
|
26
|
+
|
27
|
+
# each2 is exactly as the name sounds
|
28
|
+
# it takes from an array two at a time
|
29
|
+
# until it hits the end of the array
|
30
|
+
# as such, all the items except for first
|
31
|
+
# and last are observed twice
|
32
|
+
def each2 &block
|
33
|
+
count.times do |n|
|
34
|
+
yield self[n], self[n+1] unless n + 1 == count
|
35
|
+
end # count n
|
36
|
+
end # each2
|
37
|
+
|
38
|
+
private
|
39
|
+
def p_bisearch_internal s, f, target, right_flag, &eq
|
40
|
+
|
41
|
+
mid = (f + s)/ 2
|
42
|
+
return f if f == s
|
43
|
+
return s if count < 2
|
44
|
+
result = yield target, self[mid]
|
45
|
+
return mid if 0 == result
|
46
|
+
if s + 1 == f
|
47
|
+
if right_flag
|
48
|
+
return s if yield(target, self[s]) <= 0 # target == self[s] or target < self[s]
|
49
|
+
return f
|
50
|
+
else
|
51
|
+
return f if yield(target, self[f]) >= 0 # target == self[f] or target > self[f]
|
52
|
+
return s
|
53
|
+
end
|
54
|
+
end # if
|
55
|
+
return p_bisearch_internal s, mid, target, right_flag, &eq if -1 == result
|
56
|
+
return p_bisearch_internal mid, f, target, right_flag, &eq if 1 == result
|
57
|
+
end # p_bisearch_internal
|
58
|
+
end # Array
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# class methods
|
2
|
+
|
3
|
+
module Tsundere
|
4
|
+
module ClassMethods
|
5
|
+
attr_reader :look_array, :look_table, :rank_table
|
6
|
+
attr_accessor :permission_table, :rank_table
|
7
|
+
|
8
|
+
def attr_tsundere *attributes, opts
|
9
|
+
attr_looker *attributes, opts
|
10
|
+
end # attr_tsundere
|
11
|
+
|
12
|
+
def attr_looker *attributes, opts
|
13
|
+
attr_modifier_thing *attributes, opts.merge( :type => :looker )
|
14
|
+
end # attr_looker
|
15
|
+
|
16
|
+
def attr_toucher *attributes, opts
|
17
|
+
attr_modifier_thing *attributes, opts.merge( :type => :toucher )
|
18
|
+
end # attr_toucher
|
19
|
+
|
20
|
+
# Yes, I realize this function looks like crap, but it's late, I'm tired
|
21
|
+
# and this project is due really soon and I need sleep before I die. I'll
|
22
|
+
# refactor this later. I swear.
|
23
|
+
def attr_modifier_thing *attributes, opts
|
24
|
+
@rank_table ||= {}
|
25
|
+
@permission_table ||= {}
|
26
|
+
[:looker, :toucher].each do |thing|
|
27
|
+
@permission_table[thing] ||= {
|
28
|
+
:array => [] ,
|
29
|
+
:table => {}
|
30
|
+
} # looker
|
31
|
+
end # each thing
|
32
|
+
type = opts[:type]
|
33
|
+
perm = opts[:as]
|
34
|
+
case perm.class.to_s
|
35
|
+
when 'Hash'
|
36
|
+
perm.each do |key, lvl|
|
37
|
+
@rank_table[key] = lvl
|
38
|
+
|
39
|
+
# FIXME: We really should not have to call sort here,
|
40
|
+
# but for some reason the tree isn't being constructed
|
41
|
+
# properly (i.e. the test won't pass), so I decided to
|
42
|
+
# just say "fuck it" and put in a sort sort
|
43
|
+
warn "FixMe: Take out this godawful sort from this insert by fixing the array extension and passing the array_spec"
|
44
|
+
ind = permission_table[type][:array].binary_search_raw([lvl, attributes]) { |a1, a2| a1.first <=> a2.first }
|
45
|
+
permission_table[type][:array].insert(ind, [lvl, attributes]).sort! { |a1, a2| a1.first <=> a2.first }
|
46
|
+
end # each perm
|
47
|
+
when 'Fixnum', 'Integer', 'Float'
|
48
|
+
ind = permission_table[type][:array].binary_search_raw([perm, attributes]) { |a1, a2| a1.first <=> a2.first }
|
49
|
+
permission_table[type][:array].insert(ind, [perm, attributes]).sort! { |a1, a2| a1.first <=> a2.first }
|
50
|
+
when 'String', 'Symbol'
|
51
|
+
attributes.each do |attr|
|
52
|
+
(permission_table[type][:table][perm] ||= []) << attr
|
53
|
+
end # each attr
|
54
|
+
end # perm class
|
55
|
+
end # attr_toucher
|
56
|
+
end # ClassMethods
|
57
|
+
end # Tsundere
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
# Imouto class; aka, the tsundere proxy
|
3
|
+
module Tsundere
|
4
|
+
class Imouto
|
5
|
+
def initialize parent, level
|
6
|
+
@parent = parent
|
7
|
+
@level = level
|
8
|
+
end # initialize
|
9
|
+
|
10
|
+
def method_missing meth, *args, &block
|
11
|
+
if @parent.respond_to? meth
|
12
|
+
if @parent.dere_for? @level, meth
|
13
|
+
@parent.send(meth, *args, &block) unless block.nil?
|
14
|
+
@parent.send(meth, *args) if block.nil?
|
15
|
+
else
|
16
|
+
return "Sorry #{@level}, you can't #{meth} me!"
|
17
|
+
end # if-else
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end # method_missing
|
22
|
+
end # imouto
|
23
|
+
end # Tsundere
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# tsundere instance module
|
2
|
+
module Tsundere
|
3
|
+
def tsundere_for(duck)
|
4
|
+
level = p_retrieve_level_or_rank duck
|
5
|
+
Imouto.new self, level
|
6
|
+
end # tsundere_for
|
7
|
+
|
8
|
+
def dere_for? lvl, meth
|
9
|
+
return false if lvl.nil?
|
10
|
+
if self.class.rank_table[lvl].is_a? Array and self.class.rank_table[lvl].include? meth
|
11
|
+
return true
|
12
|
+
else
|
13
|
+
level = self.class.rank_table[lvl.to_sym] if lvl.is_a? Symbol or lvl.is_a? String
|
14
|
+
level ||= lvl
|
15
|
+
start_ind = self.class.permission_table[:looker][:array].binary_search_raw([level, [meth]], :left => true) { |a1, a2| a1.first <=> a2.first }
|
16
|
+
flag = false
|
17
|
+
(start_ind+1).times do |n|
|
18
|
+
flag = self.class.permission_table[:looker][:array][n].last.include? meth
|
19
|
+
break flag if flag
|
20
|
+
end # times
|
21
|
+
return flag
|
22
|
+
end # if-else
|
23
|
+
end # dere_for?
|
24
|
+
|
25
|
+
private
|
26
|
+
def p_retrieve_level_or_rank duck
|
27
|
+
case duck.class.to_s
|
28
|
+
when String.to_s, Fixnum.to_s, Float.to_s, Integer.to_s, Symbol.to_s
|
29
|
+
duck
|
30
|
+
when Hash.to_s
|
31
|
+
duck[:level] if duck.has_key? :level
|
32
|
+
duck[:rank] if duck.has_key? :rank
|
33
|
+
else
|
34
|
+
duck.level if duck.respond_to? :level
|
35
|
+
duck.rank if duck.respond_to? :rank
|
36
|
+
end # duck class
|
37
|
+
end # level or rank
|
38
|
+
end # Tsundere
|
data/lib/tsundere.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# Tsundere module
|
2
|
+
# tsun tsun
|
3
|
+
# dere dere
|
4
|
+
require_relative "./tsundere/array"
|
5
|
+
require_relative "./tsundere/class_methods"
|
6
|
+
require_relative "./tsundere/instance_methods"
|
7
|
+
require_relative "./tsundere/imouto"
|
8
|
+
module Tsundere
|
9
|
+
def self.included(base)
|
10
|
+
base.extend ClassMethods
|
11
|
+
end # self.included
|
12
|
+
end # Tsundere
|
data/spec/array_spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'debugger'
|
3
|
+
describe Array do
|
4
|
+
describe "binary search raw" do
|
5
|
+
before :each do
|
6
|
+
@array = [0,1,2,3,4,5,6,7,8,9]
|
7
|
+
end # each
|
8
|
+
10.times do |n|
|
9
|
+
it "should have decent coverage #{n}" do
|
10
|
+
@array.binary_search_raw(n).should eq n
|
11
|
+
end # it
|
12
|
+
it "should have decent coverage #{n} lean left" do
|
13
|
+
@array.binary_search_raw(n, :left => true).should eq n
|
14
|
+
end # it
|
15
|
+
it "should given #{n-0.5} it should get index #{n}" do
|
16
|
+
# debugger
|
17
|
+
@array.binary_search_raw(n - 0.5).should eq n
|
18
|
+
end # it
|
19
|
+
it "should given #{n+0.5} it should get index #{n}" do
|
20
|
+
# debugger
|
21
|
+
@array.binary_search_raw(n + 0.5, :left => true).should eq n
|
22
|
+
end # it
|
23
|
+
end # each n
|
24
|
+
|
25
|
+
it "should handle the empty array" do
|
26
|
+
[].binary_search_raw(4).should eq 0
|
27
|
+
end # it
|
28
|
+
it "should handle odd input" do
|
29
|
+
@array.binary_search_raw(-1).should eq 0
|
30
|
+
end # it
|
31
|
+
it "should handle odd input on the big end " do
|
32
|
+
@array.binary_search_raw(11).should eq 9
|
33
|
+
end # it
|
34
|
+
|
35
|
+
it "should handle the empty array left" do
|
36
|
+
[].binary_search_raw(4, :left => true).should eq 0
|
37
|
+
end # it
|
38
|
+
it "should handle odd input left" do
|
39
|
+
@array.binary_search_raw(-1, :left => true).should eq 0
|
40
|
+
end # it
|
41
|
+
it "should handle odd input on the big end left" do
|
42
|
+
@array.binary_search_raw(11, :left => true).should eq 9
|
43
|
+
end # it
|
44
|
+
end # bsr
|
45
|
+
|
46
|
+
describe "construction" do
|
47
|
+
it "should construct an ordered array" do
|
48
|
+
@array = []
|
49
|
+
10.times do
|
50
|
+
val = rand(100)
|
51
|
+
ind = @array.binary_search_raw(val)
|
52
|
+
@array.insert(ind, val)
|
53
|
+
end # 10 times
|
54
|
+
|
55
|
+
@array.count.should eq 10
|
56
|
+
@array.should eq @array.sort
|
57
|
+
end # it
|
58
|
+
end # construction
|
59
|
+
end # Array
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Foobar
|
4
|
+
include Tsundere
|
5
|
+
attr_looker :admin_only, :as => :admin
|
6
|
+
attr_looker :user_and_above, :as => { :user => 4 }
|
7
|
+
attr_looker :level4, :as => 4
|
8
|
+
|
9
|
+
def admin_only
|
10
|
+
5
|
11
|
+
end # admin_only
|
12
|
+
|
13
|
+
def user_and_above
|
14
|
+
6
|
15
|
+
end
|
16
|
+
|
17
|
+
def level4
|
18
|
+
7
|
19
|
+
end
|
20
|
+
end # Foobar
|
21
|
+
|
22
|
+
describe Foobar do
|
23
|
+
describe "Included functionality" do
|
24
|
+
it "should have the permission table" do
|
25
|
+
Foobar.permission_table.should_not be_nil
|
26
|
+
end # it
|
27
|
+
it "should have the rank table" do
|
28
|
+
Foobar.rank_table.should_not be_nil
|
29
|
+
end # it
|
30
|
+
it "should have the user entry in the rank table" do
|
31
|
+
Foobar.rank_table[:user].should eq 4
|
32
|
+
end # it
|
33
|
+
end # included
|
34
|
+
end # foobar
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class StereotypicalLoli
|
4
|
+
include Tsundere
|
5
|
+
attr_looker :allow_stranger, :as => { :stranger => 1 }
|
6
|
+
attr_looker :allow_shiriai, :as => { :shiriai => 2 }
|
7
|
+
attr_looker :allow_tomodachi, :as => { :tomodachi => 3 }
|
8
|
+
attr_looker :allow_osanajimi, :as => { :osanajimi => 4 }
|
9
|
+
attr_looker :allow_senpai, :as => { :senpai => 5 }
|
10
|
+
attr_looker :allow_oneechan, :as => { :oneechan => 6 }
|
11
|
+
attr_looker :allow_oniichan, :as => { :oniichan => 7 }
|
12
|
+
|
13
|
+
def allow_oniichan
|
14
|
+
7
|
15
|
+
end
|
16
|
+
|
17
|
+
def allow_oneechan
|
18
|
+
6
|
19
|
+
end
|
20
|
+
|
21
|
+
def allow_senpai
|
22
|
+
5
|
23
|
+
end
|
24
|
+
|
25
|
+
def allow_osanajimi
|
26
|
+
4
|
27
|
+
end
|
28
|
+
|
29
|
+
def allow_tomodachi
|
30
|
+
3
|
31
|
+
end
|
32
|
+
|
33
|
+
def allow_shiriai
|
34
|
+
2
|
35
|
+
end
|
36
|
+
|
37
|
+
def allow_stranger
|
38
|
+
1
|
39
|
+
end
|
40
|
+
end # StereotypicalLoli
|
41
|
+
describe StereotypicalLoli do
|
42
|
+
describe "access" do
|
43
|
+
before :each do
|
44
|
+
@loli = StereotypicalLoli.new
|
45
|
+
end # each
|
46
|
+
it "should allow oniichan to do everything" do
|
47
|
+
@loli.tsundere_for(:oniichan).allow_oniichan.should eq 7
|
48
|
+
@loli.tsundere_for(:oniichan).allow_oneechan.should eq 6
|
49
|
+
@loli.tsundere_for(:oniichan).allow_senpai.should eq 5
|
50
|
+
@loli.tsundere_for(:oniichan).allow_osanajimi.should eq 4
|
51
|
+
@loli.tsundere_for(:oniichan).allow_tomodachi.should eq 3
|
52
|
+
@loli.tsundere_for(:oniichan).allow_shiriai.should eq 2
|
53
|
+
@loli.tsundere_for(:oniichan).allow_stranger.should eq 1
|
54
|
+
end # it
|
55
|
+
it "should not allow a regular friend to touch where only oniichan can touch" do
|
56
|
+
@loli.tsundere_for(:tomodachi).allow_oniichan.should =~ /sorry/i
|
57
|
+
@loli.tsundere_for(:tomodachi).allow_oneechan.should =~ /sorry/i
|
58
|
+
@loli.tsundere_for(:tomodachi).allow_senpai.should =~ /sorry/i
|
59
|
+
@loli.tsundere_for(:tomodachi).allow_osanajimi.should =~ /sorry/i
|
60
|
+
end # it
|
61
|
+
it "should allow a regular friend to do friendzone stuff" do
|
62
|
+
@loli.tsundere_for(:tomodachi).allow_tomodachi.should eq 3
|
63
|
+
@loli.tsundere_for(:tomodachi).allow_shiriai.should eq 2
|
64
|
+
@loli.tsundere_for(:tomodachi).allow_stranger.should eq 1
|
65
|
+
end # it
|
66
|
+
it "should not allow a friend to get out of the friend zone" do
|
67
|
+
@loli.tsundere_for(:tomodachi).allow_oniichan.should =~ /sorry/i
|
68
|
+
end # it
|
69
|
+
end # access
|
70
|
+
end # Footbar
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.expand_path("../../lib/tsundere", __FILE__)
|
2
|
+
require 'rspec/autorun'
|
3
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
4
|
+
# in spec/support/ and its subdirectories.
|
5
|
+
# Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
|
6
|
+
|
7
|
+
# Require all the factories
|
8
|
+
# Dir[Rails.root.join("spec/factories/*.rb")].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
# ## Mock Framework
|
12
|
+
#
|
13
|
+
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
|
14
|
+
#
|
15
|
+
# config.mock_with :mocha
|
16
|
+
# config.mock_with :flexmock
|
17
|
+
# config.mock_with :rr
|
18
|
+
|
19
|
+
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
|
20
|
+
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
|
21
|
+
|
22
|
+
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
23
|
+
# examples within a transaction, remove the following line or assign false
|
24
|
+
# instead of true.
|
25
|
+
# config.use_transactional_fixtures = true
|
26
|
+
|
27
|
+
# If true, the base class of anonymous controllers will be inferred
|
28
|
+
# automatically. This will be the default behavior in future versions of
|
29
|
+
# rspec-rails.
|
30
|
+
# config.infer_base_class_for_anonymous_controllers = false
|
31
|
+
|
32
|
+
# Run specs in random order to surface order dependencies. If you find an
|
33
|
+
# order dependency and want to debug it, you can fix the order by providing
|
34
|
+
# the seed, which is printed after each run.
|
35
|
+
# --seed 1234
|
36
|
+
config.order = "random"
|
37
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'tsundere'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
data/tsundere.gemspec
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "tsundere"
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Thomas Chen"]
|
12
|
+
s.date = "2012-12-11"
|
13
|
+
s.description = "Any given object can implement the tsundere interface. Once implemented, a tsundere object will behave differently based upon who is calling it."
|
14
|
+
s.email = "foxnewsnetwork@gmail.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"LICENSE.txt",
|
25
|
+
"README.markdown",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"lib/tsundere.rb",
|
29
|
+
"lib/tsundere/array.rb",
|
30
|
+
"lib/tsundere/class_methods.rb",
|
31
|
+
"lib/tsundere/imouto.rb",
|
32
|
+
"lib/tsundere/instance_methods.rb",
|
33
|
+
"spec/array_spec.rb",
|
34
|
+
"spec/class_methods_spec.rb",
|
35
|
+
"spec/instance_methods_spec.rb",
|
36
|
+
"spec/spec_helper.rb",
|
37
|
+
"spec/tsundere_spec.rb",
|
38
|
+
"test/helper.rb",
|
39
|
+
"test/test_tsundere.rb",
|
40
|
+
"tsundere.gemspec"
|
41
|
+
]
|
42
|
+
s.homepage = "http://github.com/foxnewsnetwork/tsundere"
|
43
|
+
s.licenses = ["MIT"]
|
44
|
+
s.require_paths = ["lib"]
|
45
|
+
s.rubygems_version = "1.8.24"
|
46
|
+
s.summary = "object buffer for graceful managment of permission"
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
s.specification_version = 3
|
50
|
+
|
51
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
52
|
+
s.add_development_dependency(%q<debugger>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.12.0"])
|
54
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
55
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
56
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.2.3"])
|
57
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
58
|
+
else
|
59
|
+
s.add_dependency(%q<debugger>, [">= 0"])
|
60
|
+
s.add_dependency(%q<rspec>, ["~> 2.12.0"])
|
61
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
62
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
63
|
+
s.add_dependency(%q<bundler>, ["~> 1.2.3"])
|
64
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
65
|
+
end
|
66
|
+
else
|
67
|
+
s.add_dependency(%q<debugger>, [">= 0"])
|
68
|
+
s.add_dependency(%q<rspec>, ["~> 2.12.0"])
|
69
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
70
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
71
|
+
s.add_dependency(%q<bundler>, ["~> 1.2.3"])
|
72
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
metadata
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tsundere
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thomas Chen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: debugger
|
16
|
+
requirement: !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: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.12.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: 2.12.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: shoulda
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
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: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rdoc
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3.12'
|
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: '3.12'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: bundler
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.2.3
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.2.3
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: jeweler
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.8.4
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.8.4
|
110
|
+
description: Any given object can implement the tsundere interface. Once implemented,
|
111
|
+
a tsundere object will behave differently based upon who is calling it.
|
112
|
+
email: foxnewsnetwork@gmail.com
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files:
|
116
|
+
- LICENSE.txt
|
117
|
+
- README.markdown
|
118
|
+
files:
|
119
|
+
- .document
|
120
|
+
- .rspec
|
121
|
+
- Gemfile
|
122
|
+
- Gemfile.lock
|
123
|
+
- LICENSE.txt
|
124
|
+
- README.markdown
|
125
|
+
- Rakefile
|
126
|
+
- VERSION
|
127
|
+
- lib/tsundere.rb
|
128
|
+
- lib/tsundere/array.rb
|
129
|
+
- lib/tsundere/class_methods.rb
|
130
|
+
- lib/tsundere/imouto.rb
|
131
|
+
- lib/tsundere/instance_methods.rb
|
132
|
+
- spec/array_spec.rb
|
133
|
+
- spec/class_methods_spec.rb
|
134
|
+
- spec/instance_methods_spec.rb
|
135
|
+
- spec/spec_helper.rb
|
136
|
+
- spec/tsundere_spec.rb
|
137
|
+
- test/helper.rb
|
138
|
+
- test/test_tsundere.rb
|
139
|
+
- tsundere.gemspec
|
140
|
+
homepage: http://github.com/foxnewsnetwork/tsundere
|
141
|
+
licenses:
|
142
|
+
- MIT
|
143
|
+
post_install_message:
|
144
|
+
rdoc_options: []
|
145
|
+
require_paths:
|
146
|
+
- lib
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
+
none: false
|
149
|
+
requirements:
|
150
|
+
- - ! '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
segments:
|
154
|
+
- 0
|
155
|
+
hash: 4316759713734857947
|
156
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
|
+
none: false
|
158
|
+
requirements:
|
159
|
+
- - ! '>='
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
requirements: []
|
163
|
+
rubyforge_project:
|
164
|
+
rubygems_version: 1.8.24
|
165
|
+
signing_key:
|
166
|
+
specification_version: 3
|
167
|
+
summary: object buffer for graceful managment of permission
|
168
|
+
test_files: []
|