ember 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/HISTORY +79 -0
- data/INSTALL +31 -0
- data/MANUAL +25 -0
- data/README +54 -0
- data/THEORY +151 -0
- data/USAGE +250 -0
- data/bin/ember +58 -20
- data/doc/ann.xml +93 -0
- data/doc/api/Ember.html +436 -0
- data/doc/api/Ember/Template.html +774 -0
- data/doc/api/Ember/Template/Program.html +877 -0
- data/doc/api/Ember/Template/Program/Statement.html +181 -0
- data/doc/api/_index.html +139 -0
- data/doc/api/class_list.html +36 -0
- data/doc/api/css/common.css +1 -0
- data/doc/api/css/full_list.css +50 -0
- data/doc/api/css/style.css +273 -0
- data/doc/api/file.LICENSE.html +73 -0
- data/doc/api/file_list.html +38 -0
- data/doc/api/frames.html +13 -0
- data/doc/api/index.html +72 -13
- data/doc/api/js/app.js +111 -0
- data/doc/api/js/full_list.js +117 -0
- data/doc/api/js/{jquery-1.3.2.min.js → jquery.js} +0 -0
- data/doc/api/method_list.html +179 -0
- data/doc/api/top-level-namespace.html +87 -0
- data/doc/index.html +1353 -682
- data/inochi.opts +31 -0
- data/lib/ember.rb +1 -15
- data/lib/ember/inochi.rb +103 -0
- data/lib/ember/template.rb +66 -78
- data/test/combinatorics.rb +188 -0
- data/test/ember/template_test.rb +137 -0
- data/test/runner +25 -0
- data/test/test_helper.rb +5 -0
- metadata +61 -51
- data/doc/api/apple-touch-icon.png +0 -0
- data/doc/api/classes/Ember.html +0 -61
- data/doc/api/classes/Ember/Template.html +0 -413
- data/doc/api/classes/Ember/Template/Program.html +0 -60
- data/doc/api/created.rid +0 -1
- data/doc/api/css/main.css +0 -263
- data/doc/api/css/panel.css +0 -383
- data/doc/api/css/reset.css +0 -53
- data/doc/api/favicon.ico +0 -0
- data/doc/api/files/LICENSE.html +0 -76
- data/doc/api/files/lib/ember/template_rb.html +0 -66
- data/doc/api/files/lib/ember_rb.html +0 -63
- data/doc/api/i/arrows.png +0 -0
- data/doc/api/i/results_bg.png +0 -0
- data/doc/api/i/tree_bg.png +0 -0
- data/doc/api/js/jquery-effect.js +0 -593
- data/doc/api/js/main.js +0 -22
- data/doc/api/js/searchdoc.js +0 -628
- data/doc/api/panel/index.html +0 -71
- data/doc/api/panel/search_index.js +0 -1
- data/doc/api/panel/tree.js +0 -1
- data/doc/history.erb +0 -34
- data/doc/index.erb +0 -11
- data/doc/intro.erb +0 -53
- data/doc/setup.erb +0 -78
- data/doc/usage.erb +0 -280
- data/rakefile +0 -14
- data/test/ember.rb +0 -17
- data/test/ember/template.rb +0 -141
data/inochi.opts
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
##
|
2
|
+
# Location where project documentation will be uploaded by `inochi pub:doc`.
|
3
|
+
# This value can utilize any remote/destination syntax supported by `rsync`.
|
4
|
+
#
|
5
|
+
:pub_doc_target: ~/www/lib/ember
|
6
|
+
|
7
|
+
##
|
8
|
+
# Options for the `rsync` command used to upload this project's documentation.
|
9
|
+
#
|
10
|
+
:pub_doc_options: --verbose --compress --archive --update --delete
|
11
|
+
|
12
|
+
##
|
13
|
+
# Arbitrary Ruby code that will configure this project's RubyGem before it
|
14
|
+
# is built by `inochi gem`. This code has access to a local variable named
|
15
|
+
# `gem` which holds a Gem::Specification object representing this project.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
#
|
19
|
+
# :gem_spec_logic: |
|
20
|
+
# # show the Inochi-provided specification for this project's RubyGem
|
21
|
+
# puts gem
|
22
|
+
#
|
23
|
+
# # add files that are outside this project directory to the RubyGem
|
24
|
+
# gem.files += FileList['/some/outside/**/*.files']
|
25
|
+
#
|
26
|
+
# # omit some files in this project's directory from the RubyGem
|
27
|
+
# gem.files.exclude '{some*files,in_this,project/**/directory}'
|
28
|
+
#
|
29
|
+
# # and so on... anything is possible! use your imagination!
|
30
|
+
#
|
31
|
+
:gem_spec_logic: |
|
data/lib/ember.rb
CHANGED
@@ -1,16 +1,2 @@
|
|
1
|
-
|
2
|
-
# Copyright protects this work.
|
3
|
-
# See LICENSE file for details.
|
4
|
-
#++
|
5
|
-
|
6
|
-
require 'rubygems'
|
7
|
-
gem 'inochi', '~> 1'
|
8
|
-
require 'inochi'
|
9
|
-
|
10
|
-
Inochi.init :Ember,
|
11
|
-
:version => '0.0.1',
|
12
|
-
:release => '2009-10-03',
|
13
|
-
:website => 'http://snk.tuxfamily.org/lib/ember/',
|
14
|
-
:tagline => 'eRuby template processor'
|
15
|
-
|
1
|
+
require 'ember/inochi'
|
16
2
|
require 'ember/template'
|
data/lib/ember/inochi.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
module Ember
|
2
|
+
|
3
|
+
##
|
4
|
+
# Official name of this project.
|
5
|
+
#
|
6
|
+
PROJECT = "Ember"
|
7
|
+
|
8
|
+
##
|
9
|
+
# Short single-line description of this project.
|
10
|
+
#
|
11
|
+
TAGLINE = "eRuby template processor"
|
12
|
+
|
13
|
+
##
|
14
|
+
# Address of this project's official home page.
|
15
|
+
#
|
16
|
+
WEBSITE = "http://snk.tuxfamily.org/lib/ember/"
|
17
|
+
|
18
|
+
##
|
19
|
+
# Number of this release of this project.
|
20
|
+
#
|
21
|
+
VERSION = "0.1.0"
|
22
|
+
|
23
|
+
##
|
24
|
+
# Date of this release of this project.
|
25
|
+
#
|
26
|
+
RELDATE = "2010-04-03"
|
27
|
+
|
28
|
+
##
|
29
|
+
# Description of this release of this project.
|
30
|
+
#
|
31
|
+
def self.inspect
|
32
|
+
"#{PROJECT} #{VERSION} (#{RELDATE})"
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Location of this release of this project.
|
37
|
+
#
|
38
|
+
INSTDIR = File.expand_path('../../..', __FILE__)
|
39
|
+
|
40
|
+
##
|
41
|
+
# RubyGems required by this project during runtime.
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
#
|
45
|
+
# RUNTIME = {
|
46
|
+
# # this project needs exactly version 1.2.3 of the "an_example" gem
|
47
|
+
# "an_example" => [ "1.2.3" ],
|
48
|
+
#
|
49
|
+
# # this project needs at least version 1.2 (but not
|
50
|
+
# # version 1.2.4 or newer) of the "another_example" gem
|
51
|
+
# "another_example" => [ ">= 1.2" , "< 1.2.4" ],
|
52
|
+
#
|
53
|
+
# # this project needs any version of the "yet_another_example" gem
|
54
|
+
# "yet_another_example" => [],
|
55
|
+
# }
|
56
|
+
#
|
57
|
+
RUNTIME = {}
|
58
|
+
|
59
|
+
##
|
60
|
+
# RubyGems required by this project during development.
|
61
|
+
#
|
62
|
+
# @example
|
63
|
+
#
|
64
|
+
# DEVTIME = {
|
65
|
+
# # this project needs exactly version 1.2.3 of the "an_example" gem
|
66
|
+
# "an_example" => [ "1.2.3" ],
|
67
|
+
#
|
68
|
+
# # this project needs at least version 1.2 (but not
|
69
|
+
# # version 1.2.4 or newer) of the "another_example" gem
|
70
|
+
# "another_example" => [ ">= 1.2" , "< 1.2.4" ],
|
71
|
+
#
|
72
|
+
# # this project needs any version of the "yet_another_example" gem
|
73
|
+
# "yet_another_example" => [],
|
74
|
+
# }
|
75
|
+
#
|
76
|
+
DEVTIME = {
|
77
|
+
"inochi" => [ "~> 2" ], # for managing this project
|
78
|
+
"dfect" => [ "~> 2" ], # for unit testing
|
79
|
+
}
|
80
|
+
|
81
|
+
##
|
82
|
+
# Loads the correct version (as defined by the {RUNTIME} or {DEVTIME}
|
83
|
+
# constant in this module) of the given gem or the gem that contains
|
84
|
+
# the given library.
|
85
|
+
#
|
86
|
+
def self.require gem_name_or_library
|
87
|
+
# prepare the correct version of the gem for loading
|
88
|
+
if respond_to? :gem
|
89
|
+
gem_name = gem_name_or_library.to_s.sub(%r{/.*$}, '')
|
90
|
+
if gem_version = RUNTIME[gem_name] || DEVTIME[gem_name]
|
91
|
+
begin
|
92
|
+
gem gem_name, *gem_version
|
93
|
+
rescue LoadError => error
|
94
|
+
warn "#{self.inspect}: #{error}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# do the loading
|
100
|
+
super
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
data/lib/ember/template.rb
CHANGED
@@ -1,8 +1,3 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright protects this work.
|
3
|
-
# See LICENSE file for details.
|
4
|
-
#++
|
5
|
-
|
6
1
|
require 'pathname'
|
7
2
|
|
8
3
|
module Ember
|
@@ -13,53 +8,44 @@ module Ember
|
|
13
8
|
#
|
14
9
|
# This processor transforms the given input
|
15
10
|
# into an executable Ruby program (provided
|
16
|
-
# by the #program
|
17
|
-
# executed by the #render
|
11
|
+
# by the {#program} method) which is then
|
12
|
+
# executed by the {#render} method on demand.
|
18
13
|
#
|
19
14
|
# eRuby directives that contribute to the output of
|
20
15
|
# the given template are called "vocal" directives.
|
21
16
|
# Those that do not are called "silent" directives.
|
22
17
|
#
|
23
|
-
#
|
18
|
+
# @option options [String] :result_variable ("_erbout")
|
24
19
|
#
|
25
|
-
# [:result_variable]
|
26
20
|
# Name of the variable which stores the result of
|
27
21
|
# template evaluation during template evaluation.
|
28
22
|
#
|
29
|
-
#
|
23
|
+
# @option options [Boolean] :continue_result (false)
|
30
24
|
#
|
31
|
-
# [:continue_result]
|
32
25
|
# Append to the result variable if it already exists?
|
33
26
|
#
|
34
|
-
#
|
27
|
+
# @option options [String] :source_file ("SOURCE")
|
35
28
|
#
|
36
|
-
# [:source_file]
|
37
29
|
# Name of the file which contains the given input. This
|
38
30
|
# is shown in stack traces when reporting error messages.
|
39
31
|
#
|
40
|
-
#
|
32
|
+
# @option options [Integer] :source_line (1)
|
41
33
|
#
|
42
|
-
# [:source_line]
|
43
34
|
# Line number at which the given input exists in the :source_file.
|
44
35
|
# This is shown in stack traces when reporting error messages.
|
45
36
|
#
|
46
|
-
#
|
37
|
+
# @option options [Boolean] :shorthand (false)
|
47
38
|
#
|
48
|
-
# [:shorthand]
|
49
39
|
# Treat lines beginning with "%" as eRuby directives?
|
50
40
|
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
# [:infer_end]
|
54
|
-
# Add missing <% end %> statements based on indentation?
|
41
|
+
# @option options [Boolean] :infer_end (false)
|
55
42
|
#
|
56
|
-
#
|
43
|
+
# Add missing +<% end %>+ statements based on indentation?
|
57
44
|
#
|
58
|
-
# [:unindent
|
59
|
-
# Unindent the content of eRuby blocks (everything
|
60
|
-
# between <% do %> ... <% end %>) hierarchically?
|
45
|
+
# @option options [Boolean] :unindent (false)
|
61
46
|
#
|
62
|
-
#
|
47
|
+
# Unindent the content of eRuby blocks---that is everything
|
48
|
+
# between the +<% do %>+ and +<% end %>+ tags---hierarchically?
|
63
49
|
#
|
64
50
|
def initialize input, options = {}
|
65
51
|
@options = options
|
@@ -79,7 +65,7 @@ module Ember
|
|
79
65
|
|
80
66
|
##
|
81
67
|
# Returns the result of executing the Ruby program for this template
|
82
|
-
# (provided by the #program
|
68
|
+
# (provided by the {#program} method) inside the given context binding.
|
83
69
|
#
|
84
70
|
def render context = TOPLEVEL_BINDING, parent_context_id = nil
|
85
71
|
context ||= @@contexts[parent_context_id] # inherit parent context
|
@@ -141,72 +127,71 @@ module Ember
|
|
141
127
|
OPERATION_EVAL_TEMPLATE_STRING = '~'
|
142
128
|
OPERATION_INSERT_PLAIN_FILE = '<'
|
143
129
|
|
144
|
-
|
130
|
+
OPERATIONS = [
|
131
|
+
OPERATION_COMMENT_LINE,
|
132
|
+
OPERATION_BEGIN_LAMBDA,
|
133
|
+
OPERATION_EVAL_EXPRESSION,
|
134
|
+
OPERATION_EVAL_TEMPLATE_FILE,
|
135
|
+
OPERATION_EVAL_TEMPLATE_STRING,
|
136
|
+
OPERATION_INSERT_PLAIN_FILE,
|
137
|
+
]
|
145
138
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
OPERATION_EVAL_TEMPLATE_FILE,
|
151
|
-
OPERATION_EVAL_TEMPLATE_STRING,
|
152
|
-
OPERATION_INSERT_PLAIN_FILE,
|
153
|
-
]
|
139
|
+
SILENT_OPERATIONS = [
|
140
|
+
OPERATION_COMMENT_LINE,
|
141
|
+
OPERATION_BEGIN_LAMBDA,
|
142
|
+
]
|
154
143
|
|
155
|
-
|
156
|
-
OPERATION_COMMENT_LINE,
|
157
|
-
OPERATION_BEGIN_LAMBDA,
|
158
|
-
]
|
144
|
+
VOCAL_OPERATIONS = OPERATIONS - SILENT_OPERATIONS
|
159
145
|
|
160
|
-
|
146
|
+
DIRECTIVE_HEAD = '<%'
|
147
|
+
DIRECTIVE_BODY = '(?:(?#
|
148
|
+
there is nothing here, before the alternation,
|
149
|
+
because we want to match the "<%%>" base case
|
150
|
+
)|[^%](?:.(?!<%))*?)'
|
151
|
+
DIRECTIVE_TAIL = '-?%>'
|
161
152
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
153
|
+
SHORTHAND_HEAD = '%'
|
154
|
+
SHORTHAND_BODY = '(?:(?#
|
155
|
+
there is nothing here, before the alternation,
|
156
|
+
because we want to match the "<%%>" base case
|
157
|
+
)|[^%].*)'
|
158
|
+
SHORTHAND_TAIL = '$'
|
168
159
|
|
169
|
-
|
170
|
-
|
171
|
-
there is nothing here before the alternation
|
172
|
-
because we want to match the "<%%>" base case
|
173
|
-
)|[^%].*)'
|
174
|
-
SHORTHAND_TAIL = '$'
|
160
|
+
NEWLINE = '\r?\n'
|
161
|
+
SPACING = '[[:blank:]]*'
|
175
162
|
|
176
|
-
|
177
|
-
SPACING = '[[:blank:]]*'
|
163
|
+
MARGIN_REGEXP = /^#{SPACING}(?=\S)/o
|
178
164
|
|
179
|
-
|
165
|
+
LAMBDA_BEGIN_REGEXP = /\b(do)\b\s*(\|.*?\|)?\s*$/
|
180
166
|
|
181
|
-
|
167
|
+
build_keyword_regexp = lambda {|*words| /\A\s*\b(#{words.join '|'})\b/ }
|
182
168
|
|
183
|
-
|
169
|
+
BLOCK_BEGIN_REGEXP = build_keyword_regexp[
|
170
|
+
# generic
|
171
|
+
:begin,
|
184
172
|
|
185
|
-
|
186
|
-
|
187
|
-
:begin,
|
173
|
+
# conditional
|
174
|
+
:if, :unless, :case,
|
188
175
|
|
189
|
-
|
190
|
-
|
176
|
+
# loops
|
177
|
+
:for, :while, :until,
|
191
178
|
|
192
|
-
|
193
|
-
|
194
|
-
|
179
|
+
# scopes
|
180
|
+
:def, :class, :module
|
181
|
+
]
|
195
182
|
|
196
183
|
BLOCK_CONTINUE_REGEXP = build_keyword_regexp[
|
197
|
-
|
198
|
-
|
184
|
+
# generic
|
185
|
+
:rescue, :ensure,
|
199
186
|
|
200
|
-
|
201
|
-
|
202
|
-
|
187
|
+
# conditional
|
188
|
+
:else, :elsif, :when
|
189
|
+
]
|
203
190
|
|
204
|
-
BLOCK_END_REGEXP
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
#:startdoc:
|
191
|
+
BLOCK_END_REGEXP = build_keyword_regexp[
|
192
|
+
# generic
|
193
|
+
:end
|
194
|
+
]
|
210
195
|
|
211
196
|
##
|
212
197
|
# Transforms the given eRuby template into an executable Ruby program.
|
@@ -237,6 +222,9 @@ module Ember
|
|
237
222
|
template = contents.zip(directives).join
|
238
223
|
end
|
239
224
|
|
225
|
+
# convert single-line comment directives into nothing
|
226
|
+
template.gsub!(/^#{SPACING}#{DIRECTIVE_HEAD}##{DIRECTIVE_BODY}#{DIRECTIVE_TAIL}#{SPACING}$/, '')
|
227
|
+
|
240
228
|
# translate template into Ruby code
|
241
229
|
@margins = []
|
242
230
|
@crowns = []
|
@@ -593,4 +581,4 @@ module Ember
|
|
593
581
|
Statement = Struct.new :type, :value
|
594
582
|
end
|
595
583
|
end
|
596
|
-
end
|
584
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# Simple combinatorics library for Ruby 1.8, 1.9, and (hopefully) beyond.
|
2
|
+
#
|
3
|
+
# (the ISC license)
|
4
|
+
#
|
5
|
+
# Copyright 2007 Suraj N. Kurapati <sunaku@gmail.com>
|
6
|
+
#
|
7
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
8
|
+
# purpose with or without fee is hereby granted, provided that the above
|
9
|
+
# copyright notice and this permission notice appear in all copies.
|
10
|
+
#
|
11
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
12
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
13
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
14
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
15
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
16
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
17
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
18
|
+
#
|
19
|
+
class Array
|
20
|
+
unless method_defined? :enumeration
|
21
|
+
##
|
22
|
+
# Returns all possible enumerations made from
|
23
|
+
# sample_size number of items from this list.
|
24
|
+
#
|
25
|
+
# @param [Integer] sample_size
|
26
|
+
# The length of each enumeration.
|
27
|
+
#
|
28
|
+
# @param [Proc] sampler
|
29
|
+
# If given, each enumeration is passed to this block.
|
30
|
+
#
|
31
|
+
def enumeration(sample_size = self.length, &sampler)
|
32
|
+
return [] if sample_size < 1
|
33
|
+
|
34
|
+
results = []
|
35
|
+
|
36
|
+
visitor = lambda do |parents|
|
37
|
+
each do |child|
|
38
|
+
result = parents + [child]
|
39
|
+
|
40
|
+
if result.length < sample_size
|
41
|
+
visitor.call result
|
42
|
+
else
|
43
|
+
yield result if block_given?
|
44
|
+
results << result
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
visitor.call []
|
50
|
+
results
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
unless method_defined? :enumerations
|
55
|
+
##
|
56
|
+
# Returns all possible enumerations of all possible lengths.
|
57
|
+
#
|
58
|
+
# @param [Proc] sampler
|
59
|
+
# If given, each enumeration is passed to this block.
|
60
|
+
#
|
61
|
+
def enumerations &sampler
|
62
|
+
all_lengths_impl :enumeration, &sampler
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
unless method_defined? :combination
|
67
|
+
##
|
68
|
+
# Returns all possible combinations made from
|
69
|
+
# sample_size number of items from this list.
|
70
|
+
#
|
71
|
+
# @param [Integer] sample_size
|
72
|
+
# The length of each combination.
|
73
|
+
#
|
74
|
+
# @param [Proc] sampler
|
75
|
+
# If given, each combination is passed to this block.
|
76
|
+
#
|
77
|
+
def combination(sample_size = self.length, &sampler)
|
78
|
+
pnk_cnk_impl(sample_size, true, &sampler)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
unless method_defined? :combinations
|
83
|
+
##
|
84
|
+
# Returns all possible combinations of all possible lengths.
|
85
|
+
#
|
86
|
+
# @param [Proc] sampler
|
87
|
+
# If given, each combination is passed to this block.
|
88
|
+
#
|
89
|
+
def combinations &sampler
|
90
|
+
all_lengths_impl :combination, &sampler
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
unless method_defined? :permutation
|
95
|
+
##
|
96
|
+
# Returns all possible permutations made from
|
97
|
+
# sample_size number of items from this list.
|
98
|
+
#
|
99
|
+
# @param [Integer] sample_size
|
100
|
+
# The length of each permutation.
|
101
|
+
#
|
102
|
+
# @param [Proc] sampler
|
103
|
+
# If given, each permutation is passed to this block.
|
104
|
+
#
|
105
|
+
def permutation(sample_size = self.length, &sampler)
|
106
|
+
pnk_cnk_impl(sample_size, false, &sampler)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
unless method_defined? :permutations
|
111
|
+
##
|
112
|
+
# Returns all possible permutations of all possible lengths.
|
113
|
+
#
|
114
|
+
# @param [Proc] sampler
|
115
|
+
# If given, each permutation is passed to this block.
|
116
|
+
#
|
117
|
+
def permutations &sampler
|
118
|
+
all_lengths_impl :permutation, &sampler
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
##
|
125
|
+
# Returns results of the given method name for all possible sample sizes.
|
126
|
+
#
|
127
|
+
def all_lengths_impl method_name, &sampler
|
128
|
+
results = []
|
129
|
+
|
130
|
+
0.upto(length) do |i|
|
131
|
+
results << __send__(method_name, i, &sampler)
|
132
|
+
end
|
133
|
+
|
134
|
+
results
|
135
|
+
end
|
136
|
+
|
137
|
+
##
|
138
|
+
# Common implementation for permutation and combination functions.
|
139
|
+
#
|
140
|
+
# @param [Integer] sample_size
|
141
|
+
# Maximum depth of traversal, at which point to stop
|
142
|
+
# further traversal and to start collecting results.
|
143
|
+
#
|
144
|
+
# @param [boolean] exclude_parents
|
145
|
+
# Prevent already visited vertices from being
|
146
|
+
# visited again in subsequent iterations?
|
147
|
+
#
|
148
|
+
def pnk_cnk_impl sample_size, exclude_parents
|
149
|
+
results = []
|
150
|
+
|
151
|
+
if sample_size >= 0 && sample_size < self.length
|
152
|
+
##
|
153
|
+
# @param [#each] parents
|
154
|
+
# list of visited vertices, including the current vertex
|
155
|
+
#
|
156
|
+
# @param [#each] children
|
157
|
+
# list of unvisited vertices adjacent to current vertex
|
158
|
+
#
|
159
|
+
# @param [Integer] depth
|
160
|
+
# current depth of the traversal tree
|
161
|
+
#
|
162
|
+
visitor = lambda do |parents, children, depth|
|
163
|
+
# traverse the graph until we reach the fringe
|
164
|
+
# vertices (leaf nodes of the traversal tree)
|
165
|
+
if depth < sample_size - 1
|
166
|
+
children.each do |c|
|
167
|
+
next_children = children - (exclude_parents ? parents : [c])
|
168
|
+
next_parents = parents + [c]
|
169
|
+
next_depth = depth + 1
|
170
|
+
|
171
|
+
visitor.call next_parents, next_children, next_depth
|
172
|
+
end
|
173
|
+
else
|
174
|
+
# now we have reached the fringe vertices
|
175
|
+
children.each do |c|
|
176
|
+
result = parents + [c]
|
177
|
+
yield result if block_given?
|
178
|
+
results << result
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
visitor.call [], self, 0
|
184
|
+
end
|
185
|
+
|
186
|
+
results
|
187
|
+
end
|
188
|
+
end
|