pinstripe 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.pinstripe +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +24 -0
- data/LICENSE +20 -0
- data/README.md +5 -0
- data/Rakefile +10 -0
- data/exe/pinstripe +4 -0
- data/lib/pinstripe/call_handler.rb +12 -0
- data/lib/pinstripe/command.rb +20 -0
- data/lib/pinstripe/commands/list_commands.rb +16 -0
- data/lib/pinstripe/commands/start_console.rb +14 -0
- data/lib/pinstripe/concern.rb +19 -0
- data/lib/pinstripe/database/row.rb +48 -0
- data/lib/pinstripe/database/table.rb +131 -0
- data/lib/pinstripe/database/table_alias_manager.rb +20 -0
- data/lib/pinstripe/database/union.rb +20 -0
- data/lib/pinstripe/database.rb +56 -0
- data/lib/pinstripe/helper.rb +20 -0
- data/lib/pinstripe/helpers.rb +8 -0
- data/lib/pinstripe/inflector/inflections.rb +122 -0
- data/lib/pinstripe/inflector.rb +28 -0
- data/lib/pinstripe/monkey_patches/pluralize.rb +8 -0
- data/lib/pinstripe/monkey_patches/require_all.rb +18 -0
- data/lib/pinstripe/monkey_patches/singularize.rb +8 -0
- data/lib/pinstripe/monkey_patches/to_params_hash.rb +20 -0
- data/lib/pinstripe/params_hash.rb +44 -0
- data/lib/pinstripe/project.rb +29 -0
- data/lib/pinstripe/registry.rb +46 -0
- data/lib/pinstripe/resource_factories/call_handler.rb +8 -0
- data/lib/pinstripe/resource_factories/env.rb +9 -0
- data/lib/pinstripe/resource_factories/environment.rb +8 -0
- data/lib/pinstripe/resource_factories/project.rb +8 -0
- data/lib/pinstripe/resource_factory.rb +32 -0
- data/lib/pinstripe/resource_provider.rb +50 -0
- data/lib/pinstripe/version.rb +3 -0
- data/lib/pinstripe/workspace.rb +8 -0
- data/lib/pinstripe.rb +24 -0
- data/package.json +15 -0
- data/pinstripe +4 -0
- data/pinstripe.gemspec +38 -0
- data/rollup.config.js +19 -0
- data/web/javascripts/_pinstripe/event_wrapper.js +29 -0
- data/web/javascripts/_pinstripe/index.js +3 -0
- data/web/javascripts/_pinstripe/initialize.js +29 -0
- data/web/javascripts/_pinstripe/node_wrapper.js +354 -0
- data/web/javascripts/_pinstripe/node_wrappers/anchor.js +56 -0
- data/web/javascripts/_pinstripe/node_wrappers/document.js +27 -0
- data/web/javascripts/_pinstripe/node_wrappers/form.js +52 -0
- data/web/javascripts/_pinstripe/node_wrappers/frame.js +72 -0
- data/web/javascripts/_pinstripe/node_wrappers/index.js +8 -0
- data/web/javascripts/_pinstripe/node_wrappers/input.js +23 -0
- data/web/javascripts/_pinstripe/node_wrappers/modal.js +36 -0
- data/web/javascripts/_pinstripe/node_wrappers/script.js +17 -0
- data/web/javascripts/_pinstripe/string_reader.js +24 -0
- data/web/javascripts/_pinstripe/url.js +94 -0
- data/web/javascripts/_pinstripe/util/benchmark.js +10 -0
- data/web/javascripts/_pinstripe/util/capitalize.js +4 -0
- data/web/javascripts/_pinstripe/util/index.js +4 -0
- data/web/javascripts/_pinstripe/util/unescape_html.js +13 -0
- data/web/javascripts/_pinstripe/virtual_node.js +156 -0
- data/yarn.lock +72 -0
- metadata +162 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f2cb947e0311ba670442c2bc3863299bf54c9d918420b44b1ebc52f8fe58b5d9
|
4
|
+
data.tar.gz: 50acc4e1919747618d584a0866e5226d58493d3e512fbd10828687c24213b884
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fed3bc212e47bc4a7eab9ffc39f4474d15511edb44216da14196801615b059be9e6993edb67e90f593c1b5b9e8610487b63ee996312460132feeee3673c26e9f
|
7
|
+
data.tar.gz: e84b52f0d8d53235a21452eda448c87639b9b22d38898a971ca94fccd251e09771e53faefbb4611feb642bb430e29c4052ac5a6fea5a1de01741852da29e5c98
|
data/.gitignore
ADDED
data/.pinstripe
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
pinstripe (0.1.2)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
minitest (5.14.0)
|
10
|
+
mysql2 (0.5.3)
|
11
|
+
rake (13.0.1)
|
12
|
+
|
13
|
+
PLATFORMS
|
14
|
+
ruby
|
15
|
+
|
16
|
+
DEPENDENCIES
|
17
|
+
bundler (~> 2.0)
|
18
|
+
minitest (~> 5.0)
|
19
|
+
mysql2 (~> 0.5)
|
20
|
+
pinstripe!
|
21
|
+
rake (~> 13.0)
|
22
|
+
|
23
|
+
BUNDLED WITH
|
24
|
+
2.0.2
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
Copyright (c) 2020 Jody Salt
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
6
|
+
in the Software without restriction, including without limitation the rights
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
9
|
+
furnished to do so, subject to the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
12
|
+
copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
data/exe/pinstripe
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
require "pinstripe/registry"
|
3
|
+
|
4
|
+
class Pinstripe::Command
|
5
|
+
|
6
|
+
extend Pinstripe::Registry
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.run(name = 'list-commands', *args)
|
13
|
+
create(name, *args).run
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
puts "No such command \"#{self.class.name}\""
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
require "pinstripe/command"
|
3
|
+
|
4
|
+
Pinstripe::Command.define "list-commands" do
|
5
|
+
|
6
|
+
def run
|
7
|
+
puts ""
|
8
|
+
puts "The following commands are available:"
|
9
|
+
puts ""
|
10
|
+
Pinstripe::Command.registered_classes.keys.sort.each do |name|
|
11
|
+
puts " * #{name}"
|
12
|
+
end
|
13
|
+
puts ""
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
require "pinstripe/command"
|
3
|
+
|
4
|
+
Pinstripe::Command.define "start-console" do
|
5
|
+
|
6
|
+
def run
|
7
|
+
require "irb"
|
8
|
+
IRB.setup nil
|
9
|
+
IRB.conf[:MAIN_CONTEXT] = IRB::Irb.new.context
|
10
|
+
require "irb/ext/multi-irb"
|
11
|
+
IRB.irb nil, Pinstripe::Workspace.new
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
module Pinstripe::Concern
|
3
|
+
|
4
|
+
def missing_method_calls
|
5
|
+
@missing_method_calls ||= []
|
6
|
+
end
|
7
|
+
|
8
|
+
def included(_module)
|
9
|
+
missing_method_calls.each do |missing_method_call|
|
10
|
+
args, block = missing_method_call
|
11
|
+
_module.send *args, &block
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(*args, &block)
|
16
|
+
missing_method_calls << [args, block]
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
class Pinstripe::Database::Row
|
3
|
+
|
4
|
+
extend Pinstripe::Registry
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
attr_accessor :table_class
|
9
|
+
|
10
|
+
def register(name, options = {})
|
11
|
+
if options[:abstract]
|
12
|
+
union_class = Pinstripe::Database::Union.for(name.pluralize, :register_if_not_exists => true)
|
13
|
+
union_class.table_classes << table_class if !union_class.table_classes.include?(table_class)
|
14
|
+
else
|
15
|
+
super(name)
|
16
|
+
@table_class = Pinstripe::Database::Table.for(name.pluralize, :register_if_not_exists => true)
|
17
|
+
field "id", "type" => "integer"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_many(name, *args, &block)
|
22
|
+
table_class.has_many(name, *args, &block)
|
23
|
+
class_eval("def #{name}; self.class.table_class.new(@database).id_eq(id).#{name}; end")
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_one(name, *args, &block)
|
27
|
+
table_class.has_one(name, *args, &block)
|
28
|
+
class_eval("def #{name}; self.class.table_class.new(@database).id_eq(id).#{name}.first; end")
|
29
|
+
end
|
30
|
+
|
31
|
+
def belongs_to(name, *args, &block)
|
32
|
+
table_class.belongs_to(name, *args, &block)
|
33
|
+
class_eval("def #{name}; self.class.table_class.new(@database).id_eq(id).#{name}.first; end")
|
34
|
+
end
|
35
|
+
|
36
|
+
def field(*args, &block)
|
37
|
+
table_class.column(*args, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(database, data = {})
|
43
|
+
@database = database
|
44
|
+
@data = data
|
45
|
+
@altered_data = {}
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
|
2
|
+
require "pinstripe/registry"
|
3
|
+
|
4
|
+
class Pinstripe::Database::Table
|
5
|
+
|
6
|
+
extend Pinstripe::Registry
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def relationships
|
11
|
+
@relationships ||= {}.to_params_hash
|
12
|
+
end
|
13
|
+
|
14
|
+
def has_many(name, options = {})
|
15
|
+
relationships[name] = {
|
16
|
+
"name" => name.to_s,
|
17
|
+
"collection_name" => name.to_s,
|
18
|
+
"from_key" => "id",
|
19
|
+
"to_key" => "#{self.name.singularize}_id",
|
20
|
+
"cascade_delete" => "true"
|
21
|
+
}
|
22
|
+
relationships[name].merge!(options)
|
23
|
+
class_eval("def #{name}; join('#{name}'); end")
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_one(name, options = {})
|
27
|
+
relationships[name] = {
|
28
|
+
"name" => name.to_s,
|
29
|
+
"collection_name" => name.pluralize,
|
30
|
+
"from_key" => "id",
|
31
|
+
"to_key" => "#{self.name.singularize}_id",
|
32
|
+
"cascade_delete" => "true"
|
33
|
+
}
|
34
|
+
relationships[name].merge!(options)
|
35
|
+
class_eval("def #{name}; join('#{name}'); end")
|
36
|
+
end
|
37
|
+
|
38
|
+
def belongs_to(name, options = {})
|
39
|
+
relationships[name] = {
|
40
|
+
"name" => name.to_s,
|
41
|
+
"collection_name" => name.pluralize,
|
42
|
+
"from_key" => "#{name}_id",
|
43
|
+
"to_key" => "id",
|
44
|
+
"cascade_delete" => "false"
|
45
|
+
}
|
46
|
+
relationships[name].merge!(options)
|
47
|
+
class_eval("def #{name}; join('#{name}'); end")
|
48
|
+
end
|
49
|
+
|
50
|
+
def columns
|
51
|
+
@columns ||= {}.to_params_hash
|
52
|
+
end
|
53
|
+
|
54
|
+
def column(name, options = {})
|
55
|
+
columns[name] = {
|
56
|
+
"name" => name.to_s,
|
57
|
+
"type" => "string"
|
58
|
+
}
|
59
|
+
columns[name].merge!(options)
|
60
|
+
class_eval("def #{name}_eq(value); where('?.`#{name}` = ?', self, value); end")
|
61
|
+
end
|
62
|
+
|
63
|
+
def scope(name, &block)
|
64
|
+
#call block with join parents as arguments
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def initialize(database, join_parent = nil, join_relationship_name = nil, table_alias_manager = Pinstripe::Database::TableAliasManager.new)
|
70
|
+
@database = database
|
71
|
+
@join_parent = join_parent
|
72
|
+
@join_relationship_name = join_relationship_name
|
73
|
+
@table_alias_manager = table_alias_manager
|
74
|
+
@joins = []
|
75
|
+
@predicates = []
|
76
|
+
@alias = table_alias_manager.generate_alias(self.class.name)
|
77
|
+
end
|
78
|
+
|
79
|
+
def clone
|
80
|
+
out = super
|
81
|
+
out.instance_eval do
|
82
|
+
@joins = @joins.clone
|
83
|
+
@predicates = @predicates.clone
|
84
|
+
end
|
85
|
+
out
|
86
|
+
end
|
87
|
+
|
88
|
+
def back(count = 1)
|
89
|
+
current = self
|
90
|
+
count.times do
|
91
|
+
previous = current
|
92
|
+
current = current.instance_eval{ @join_parent }.clone
|
93
|
+
current.instance_eval{ @joins << previous }
|
94
|
+
end
|
95
|
+
current
|
96
|
+
end
|
97
|
+
|
98
|
+
def join(relationship_name)
|
99
|
+
collection_name = self.class.relationships[relationship_name].collection_name
|
100
|
+
Pinstripe::Database::Table.create(collection_name, @database, self, relationship_name, @table_alias_manager)
|
101
|
+
end
|
102
|
+
|
103
|
+
def where(*predicate)
|
104
|
+
out = clone
|
105
|
+
out.instance_eval{ @predicates << predicate.flatten }
|
106
|
+
out
|
107
|
+
end
|
108
|
+
|
109
|
+
def first
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
def each
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
def all
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
def generate_predicate_sql
|
122
|
+
out = []
|
123
|
+
|
124
|
+
out.join(' and ')
|
125
|
+
end
|
126
|
+
|
127
|
+
def generate_select_sql
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
class Pinstripe::Database::TableAliasManager
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@alias_counters = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def generate_alias(name)
|
9
|
+
name = name.to_s
|
10
|
+
@alias_counters[name] = 0 if @alias_counters[name].nil?
|
11
|
+
@alias_counters[name] += 1
|
12
|
+
|
13
|
+
if @alias_counters[name] == 1
|
14
|
+
name
|
15
|
+
else
|
16
|
+
"#{name}#{@alias_counters[name]}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
require "pinstripe/registry"
|
3
|
+
|
4
|
+
class Pinstripe::Database::Union
|
5
|
+
|
6
|
+
extend Pinstripe::Registry
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def table_classes
|
11
|
+
@table_classes ||= []
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(database)
|
17
|
+
@database = database
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
require "mysql2"
|
3
|
+
|
4
|
+
class Pinstripe::Database
|
5
|
+
|
6
|
+
attr_reader :config
|
7
|
+
|
8
|
+
def initialize(config = {})
|
9
|
+
@config = config.to_params_hash
|
10
|
+
end
|
11
|
+
|
12
|
+
def client
|
13
|
+
@client ||= Mysql2::Client.new({
|
14
|
+
:host => @config.host || '127.0.0.1',
|
15
|
+
:port => @config.port || 3306,
|
16
|
+
:username => @config.username || 'root',
|
17
|
+
:password => @config.password || '',
|
18
|
+
:database => @config.name
|
19
|
+
})
|
20
|
+
end
|
21
|
+
|
22
|
+
def query(*query)
|
23
|
+
out = []
|
24
|
+
query = query.flatten
|
25
|
+
while(query.length > 0)
|
26
|
+
sql_fragment = query.shift.to_s
|
27
|
+
sql_fragment.gsub! /\?/ do |match|
|
28
|
+
value = query.shift
|
29
|
+
if value.kind_of?(Pinstripe::Database::Table)
|
30
|
+
value.instance_eval{ @alias }
|
31
|
+
else
|
32
|
+
sanitize(value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
out << sql_fragment
|
36
|
+
end
|
37
|
+
out.join(' ')
|
38
|
+
end
|
39
|
+
|
40
|
+
def sanitize(value)
|
41
|
+
value.kind_of?(Numeric) ? value : "'#{client.escape(value)}'"
|
42
|
+
end
|
43
|
+
|
44
|
+
def method_missing(name, *args, &block)
|
45
|
+
if args.length == 0
|
46
|
+
if Union.registered_classes[name]
|
47
|
+
Union.create(name, self)
|
48
|
+
else
|
49
|
+
Table.create(name, self)
|
50
|
+
end
|
51
|
+
else
|
52
|
+
super
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
require "pinstripe/registry"
|
3
|
+
require "pinstripe/helpers"
|
4
|
+
|
5
|
+
class Pinstripe::Helper
|
6
|
+
|
7
|
+
extend Pinstripe::Registry
|
8
|
+
|
9
|
+
include Pinstripe::Helpers
|
10
|
+
|
11
|
+
def self.register(name)
|
12
|
+
super
|
13
|
+
Pinstripe::Helpers.class_eval("def #{name}(*args, &block); ::Pinstripe::Helper.create(\"#{name}\").call(*args, &block); end")
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(*args, &block)
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
|
2
|
+
module Pinstripe::Inflector::Inflections
|
3
|
+
|
4
|
+
instance_eval do
|
5
|
+
@pluralize_rules = []
|
6
|
+
@singularize_rules = []
|
7
|
+
end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
attr_accessor :pluralize_rules
|
12
|
+
attr_accessor :singularize_rules
|
13
|
+
|
14
|
+
def plural(*args)
|
15
|
+
pluralize_rules.prepend(args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def singular(*args)
|
19
|
+
singularize_rules.prepend(args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def irregular(singular, plural)
|
23
|
+
s0 = singular[0]
|
24
|
+
srest = singular[1..-1]
|
25
|
+
|
26
|
+
p0 = plural[0]
|
27
|
+
prest = plural[1..-1]
|
28
|
+
|
29
|
+
if s0.upcase == p0.upcase
|
30
|
+
plural(/(#{s0})#{srest}$/i, '\1' + prest)
|
31
|
+
plural(/(#{p0})#{prest}$/i, '\1' + prest)
|
32
|
+
|
33
|
+
singular(/(#{s0})#{srest}$/i, '\1' + srest)
|
34
|
+
singular(/(#{p0})#{prest}$/i, '\1' + srest)
|
35
|
+
else
|
36
|
+
plural(/#{s0.upcase}(?i)#{srest}$/, p0.upcase + prest)
|
37
|
+
plural(/#{s0.downcase}(?i)#{srest}$/, p0.downcase + prest)
|
38
|
+
plural(/#{p0.upcase}(?i)#{prest}$/, p0.upcase + prest)
|
39
|
+
plural(/#{p0.downcase}(?i)#{prest}$/, p0.downcase + prest)
|
40
|
+
|
41
|
+
singular(/#{s0.upcase}(?i)#{srest}$/, s0.upcase + srest)
|
42
|
+
singular(/#{s0.downcase}(?i)#{srest}$/, s0.downcase + srest)
|
43
|
+
singular(/#{p0.upcase}(?i)#{prest}$/, s0.upcase + srest)
|
44
|
+
singular(/#{p0.downcase}(?i)#{prest}$/, s0.downcase + srest)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def uncountable(singular_and_plural)
|
49
|
+
irregular(singular_and_plural, singular_and_plural)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
plural(/$/, "s")
|
55
|
+
plural(/s$/i, "s")
|
56
|
+
plural(/^(ax|test)is$/i, '\1es')
|
57
|
+
plural(/(octop|vir)us$/i, '\1i')
|
58
|
+
plural(/(octop|vir)i$/i, '\1i')
|
59
|
+
plural(/(alias|status)$/i, '\1es')
|
60
|
+
plural(/(bu)s$/i, '\1ses')
|
61
|
+
plural(/(buffal|tomat)o$/i, '\1oes')
|
62
|
+
plural(/([ti])um$/i, '\1a')
|
63
|
+
plural(/([ti])a$/i, '\1a')
|
64
|
+
plural(/sis$/i, "ses")
|
65
|
+
plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
|
66
|
+
plural(/(hive)$/i, '\1s')
|
67
|
+
plural(/([^aeiouy]|qu)y$/i, '\1ies')
|
68
|
+
plural(/(x|ch|ss|sh)$/i, '\1es')
|
69
|
+
plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
|
70
|
+
plural(/^(m|l)ouse$/i, '\1ice')
|
71
|
+
plural(/^(m|l)ice$/i, '\1ice')
|
72
|
+
plural(/^(ox)$/i, '\1en')
|
73
|
+
plural(/^(oxen)$/i, '\1')
|
74
|
+
plural(/(quiz)$/i, '\1zes')
|
75
|
+
|
76
|
+
singular(/s$/i, "")
|
77
|
+
singular(/(ss)$/i, '\1')
|
78
|
+
singular(/(n)ews$/i, '\1ews')
|
79
|
+
singular(/([ti])a$/i, '\1um')
|
80
|
+
singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis')
|
81
|
+
singular(/(^analy)(sis|ses)$/i, '\1sis')
|
82
|
+
singular(/([^f])ves$/i, '\1fe')
|
83
|
+
singular(/(hive)s$/i, '\1')
|
84
|
+
singular(/(tive)s$/i, '\1')
|
85
|
+
singular(/([lr])ves$/i, '\1f')
|
86
|
+
singular(/([^aeiouy]|qu)ies$/i, '\1y')
|
87
|
+
singular(/(s)eries$/i, '\1eries')
|
88
|
+
singular(/(m)ovies$/i, '\1ovie')
|
89
|
+
singular(/(x|ch|ss|sh)es$/i, '\1')
|
90
|
+
singular(/^(m|l)ice$/i, '\1ouse')
|
91
|
+
singular(/(bus)(es)?$/i, '\1')
|
92
|
+
singular(/(o)es$/i, '\1')
|
93
|
+
singular(/(shoe)s$/i, '\1')
|
94
|
+
singular(/(cris|test)(is|es)$/i, '\1is')
|
95
|
+
singular(/^(a)x[ie]s$/i, '\1xis')
|
96
|
+
singular(/(octop|vir)(us|i)$/i, '\1us')
|
97
|
+
singular(/(alias|status)(es)?$/i, '\1')
|
98
|
+
singular(/^(ox)en/i, '\1')
|
99
|
+
singular(/(vert|ind)ices$/i, '\1ex')
|
100
|
+
singular(/(matr)ices$/i, '\1ix')
|
101
|
+
singular(/(quiz)zes$/i, '\1')
|
102
|
+
singular(/(database)s$/i, '\1')
|
103
|
+
|
104
|
+
irregular("person", "people")
|
105
|
+
irregular("man", "men")
|
106
|
+
irregular("child", "children")
|
107
|
+
irregular("sex", "sexes")
|
108
|
+
irregular("move", "moves")
|
109
|
+
irregular("zombie", "zombies")
|
110
|
+
|
111
|
+
uncountable "equipment"
|
112
|
+
uncountable "information"
|
113
|
+
uncountable "rice"
|
114
|
+
uncountable "money"
|
115
|
+
uncountable "species"
|
116
|
+
uncountable "series"
|
117
|
+
uncountable "fish"
|
118
|
+
uncountable "sheep"
|
119
|
+
uncountable "jeans"
|
120
|
+
uncountable "police"
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Pinstripe::Inflector
|
4
|
+
|
5
|
+
require "pinstripe/inflector/inflections"
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def pluralize(word)
|
10
|
+
word = word.to_s
|
11
|
+
Inflections.pluralize_rules.each do |rule|
|
12
|
+
pattern, replacement = rule
|
13
|
+
return word.sub(pattern, replacement) if word.match?(pattern)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def singularize(word)
|
18
|
+
word = word.to_s
|
19
|
+
Inflections.singularize_rules.each do |rule|
|
20
|
+
pattern, replacement = rule
|
21
|
+
return word.sub(pattern, replacement) if word.match?(pattern)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
module Kernel
|
3
|
+
|
4
|
+
def require_all(path)
|
5
|
+
$LOAD_PATH.each do |current_load_path|
|
6
|
+
candidate_path = "#{current_load_path}/#{path}"
|
7
|
+
require path if File.exists?("#{candidate_path}.rb") || File.exists?("#{candidate_path}.ruby")
|
8
|
+
|
9
|
+
if Dir.exists?(candidate_path)
|
10
|
+
Dir.open(candidate_path).each do |item|
|
11
|
+
item = item.sub(/(\.[^\.]+)$/, '')
|
12
|
+
require_all("#{path}/#{item}") if item != '..' && item != '.'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|