less 1.1.13 → 1.2.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/Rakefile +13 -41
  2. data/VERSION +1 -1
  3. data/bin/lessc +8 -2
  4. data/less.gemspec +13 -92
  5. data/lib/ext.rb +15 -19
  6. data/lib/less.rb +2 -2
  7. data/lib/less/command.rb +14 -15
  8. data/lib/less/engine.rb +3 -2
  9. data/lib/less/engine/grammar/common.tt +1 -1
  10. data/lib/less/engine/grammar/entity.tt +5 -5
  11. data/lib/less/engine/grammar/less.tt +107 -77
  12. data/lib/less/engine/nodes/element.rb +103 -24
  13. data/lib/less/engine/nodes/entity.rb +3 -3
  14. data/lib/less/engine/nodes/function.rb +11 -6
  15. data/lib/less/engine/nodes/literal.rb +8 -4
  16. data/lib/less/engine/nodes/property.rb +98 -38
  17. data/lib/less/engine/nodes/selector.rb +1 -1
  18. data/spec/css/css-3.css +14 -0
  19. data/spec/css/mixins-args.css +31 -0
  20. data/spec/css/variables.css +1 -0
  21. data/spec/css/whitespace.css +1 -0
  22. data/spec/engine_spec.rb +4 -3
  23. data/spec/less/css-3.less +30 -0
  24. data/spec/less/hidden.less +25 -0
  25. data/spec/less/import.less +1 -0
  26. data/spec/less/literal-css.less +11 -0
  27. data/spec/less/mixins-args.less +50 -0
  28. data/spec/less/variables.less +7 -1
  29. data/spec/less/whitespace.less +1 -0
  30. data/spec/spec_helper.rb +2 -2
  31. metadata +25 -94
  32. data/lib/vendor/treetop/.gitignore +0 -7
  33. data/lib/vendor/treetop/LICENSE +0 -19
  34. data/lib/vendor/treetop/README +0 -164
  35. data/lib/vendor/treetop/Rakefile +0 -19
  36. data/lib/vendor/treetop/benchmark/seqpar.gnuplot +0 -15
  37. data/lib/vendor/treetop/benchmark/seqpar.treetop +0 -16
  38. data/lib/vendor/treetop/benchmark/seqpar_benchmark.rb +0 -107
  39. data/lib/vendor/treetop/bin/tt +0 -28
  40. data/lib/vendor/treetop/lib/treetop.rb +0 -8
  41. data/lib/vendor/treetop/lib/treetop/bootstrap_gen_1_metagrammar.rb +0 -45
  42. data/lib/vendor/treetop/lib/treetop/compiler.rb +0 -6
  43. data/lib/vendor/treetop/lib/treetop/compiler/grammar_compiler.rb +0 -42
  44. data/lib/vendor/treetop/lib/treetop/compiler/lexical_address_space.rb +0 -17
  45. data/lib/vendor/treetop/lib/treetop/compiler/metagrammar.rb +0 -3097
  46. data/lib/vendor/treetop/lib/treetop/compiler/metagrammar.treetop +0 -408
  47. data/lib/vendor/treetop/lib/treetop/compiler/node_classes.rb +0 -19
  48. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/anything_symbol.rb +0 -18
  49. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/atomic_expression.rb +0 -14
  50. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/character_class.rb +0 -24
  51. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/choice.rb +0 -31
  52. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/declaration_sequence.rb +0 -24
  53. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/grammar.rb +0 -28
  54. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/inline_module.rb +0 -27
  55. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/nonterminal.rb +0 -13
  56. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/optional.rb +0 -19
  57. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/parenthesized_expression.rb +0 -9
  58. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/parsing_expression.rb +0 -138
  59. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/parsing_rule.rb +0 -55
  60. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/predicate.rb +0 -45
  61. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/repetition.rb +0 -55
  62. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/sequence.rb +0 -68
  63. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/terminal.rb +0 -20
  64. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/transient_prefix.rb +0 -9
  65. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/treetop_file.rb +0 -9
  66. data/lib/vendor/treetop/lib/treetop/compiler/ruby_builder.rb +0 -113
  67. data/lib/vendor/treetop/lib/treetop/ruby_extensions.rb +0 -2
  68. data/lib/vendor/treetop/lib/treetop/ruby_extensions/string.rb +0 -42
  69. data/lib/vendor/treetop/lib/treetop/runtime.rb +0 -5
  70. data/lib/vendor/treetop/lib/treetop/runtime/compiled_parser.rb +0 -105
  71. data/lib/vendor/treetop/lib/treetop/runtime/interval_skip_list.rb +0 -4
  72. data/lib/vendor/treetop/lib/treetop/runtime/interval_skip_list/head_node.rb +0 -15
  73. data/lib/vendor/treetop/lib/treetop/runtime/interval_skip_list/interval_skip_list.rb +0 -200
  74. data/lib/vendor/treetop/lib/treetop/runtime/interval_skip_list/node.rb +0 -164
  75. data/lib/vendor/treetop/lib/treetop/runtime/syntax_node.rb +0 -72
  76. data/lib/vendor/treetop/lib/treetop/runtime/terminal_parse_failure.rb +0 -16
  77. data/lib/vendor/treetop/lib/treetop/runtime/terminal_syntax_node.rb +0 -17
  78. data/lib/vendor/treetop/lib/treetop/version.rb +0 -9
  79. data/lib/vendor/treetop/spec/compiler/and_predicate_spec.rb +0 -36
  80. data/lib/vendor/treetop/spec/compiler/anything_symbol_spec.rb +0 -44
  81. data/lib/vendor/treetop/spec/compiler/character_class_spec.rb +0 -182
  82. data/lib/vendor/treetop/spec/compiler/choice_spec.rb +0 -80
  83. data/lib/vendor/treetop/spec/compiler/circular_compilation_spec.rb +0 -28
  84. data/lib/vendor/treetop/spec/compiler/failure_propagation_functional_spec.rb +0 -21
  85. data/lib/vendor/treetop/spec/compiler/grammar_compiler_spec.rb +0 -84
  86. data/lib/vendor/treetop/spec/compiler/grammar_spec.rb +0 -41
  87. data/lib/vendor/treetop/spec/compiler/nonterminal_symbol_spec.rb +0 -40
  88. data/lib/vendor/treetop/spec/compiler/not_predicate_spec.rb +0 -38
  89. data/lib/vendor/treetop/spec/compiler/one_or_more_spec.rb +0 -35
  90. data/lib/vendor/treetop/spec/compiler/optional_spec.rb +0 -37
  91. data/lib/vendor/treetop/spec/compiler/parenthesized_expression_spec.rb +0 -19
  92. data/lib/vendor/treetop/spec/compiler/parsing_rule_spec.rb +0 -32
  93. data/lib/vendor/treetop/spec/compiler/sequence_spec.rb +0 -115
  94. data/lib/vendor/treetop/spec/compiler/terminal_spec.rb +0 -81
  95. data/lib/vendor/treetop/spec/compiler/terminal_symbol_spec.rb +0 -37
  96. data/lib/vendor/treetop/spec/compiler/test_grammar.treetop +0 -7
  97. data/lib/vendor/treetop/spec/compiler/test_grammar.tt +0 -7
  98. data/lib/vendor/treetop/spec/compiler/test_grammar_do.treetop +0 -7
  99. data/lib/vendor/treetop/spec/compiler/zero_or_more_spec.rb +0 -56
  100. data/lib/vendor/treetop/spec/composition/a.treetop +0 -11
  101. data/lib/vendor/treetop/spec/composition/b.treetop +0 -11
  102. data/lib/vendor/treetop/spec/composition/c.treetop +0 -10
  103. data/lib/vendor/treetop/spec/composition/d.treetop +0 -10
  104. data/lib/vendor/treetop/spec/composition/f.treetop +0 -17
  105. data/lib/vendor/treetop/spec/composition/grammar_composition_spec.rb +0 -40
  106. data/lib/vendor/treetop/spec/composition/subfolder/e_includes_c.treetop +0 -15
  107. data/lib/vendor/treetop/spec/ruby_extensions/string_spec.rb +0 -32
  108. data/lib/vendor/treetop/spec/runtime/compiled_parser_spec.rb +0 -101
  109. data/lib/vendor/treetop/spec/runtime/interval_skip_list/delete_spec.rb +0 -147
  110. data/lib/vendor/treetop/spec/runtime/interval_skip_list/expire_range_spec.rb +0 -349
  111. data/lib/vendor/treetop/spec/runtime/interval_skip_list/insert_and_delete_node.rb +0 -385
  112. data/lib/vendor/treetop/spec/runtime/interval_skip_list/insert_spec.rb +0 -660
  113. data/lib/vendor/treetop/spec/runtime/interval_skip_list/interval_skip_list_spec.graffle +0 -6175
  114. data/lib/vendor/treetop/spec/runtime/interval_skip_list/interval_skip_list_spec.rb +0 -58
  115. data/lib/vendor/treetop/spec/runtime/interval_skip_list/palindromic_fixture.rb +0 -23
  116. data/lib/vendor/treetop/spec/runtime/interval_skip_list/palindromic_fixture_spec.rb +0 -164
  117. data/lib/vendor/treetop/spec/runtime/interval_skip_list/spec_helper.rb +0 -84
  118. data/lib/vendor/treetop/spec/runtime/syntax_node_spec.rb +0 -53
  119. data/lib/vendor/treetop/spec/spec_helper.rb +0 -106
  120. data/lib/vendor/treetop/spec/spec_suite.rb +0 -4
  121. data/lib/vendor/treetop/treetop.gemspec +0 -17
@@ -1,68 +0,0 @@
1
- module Treetop
2
- module Compiler
3
- class Sequence < ParsingExpression
4
- def compile(address, builder, parent_expression = nil)
5
- super
6
- begin_comment(self)
7
- use_vars :result, :start_index, :accumulator
8
- compile_sequence_elements(sequence_elements)
9
- builder.if__ "#{accumulator_var}.last" do
10
- assign_result "instantiate_node(#{node_class_name},input, #{start_index_var}...index, #{accumulator_var})"
11
- extend_result sequence_element_accessor_module_name if sequence_element_accessor_module_name
12
- extend_result_with_inline_module
13
- end
14
- builder.else_ do
15
- reset_index
16
- assign_failure start_index_var
17
- end
18
- end_comment(self)
19
- end
20
-
21
- def node_class_name
22
- node_class_declarations.node_class_name || 'SyntaxNode'
23
- end
24
-
25
- def compile_sequence_elements(elements)
26
- obtain_new_subexpression_address
27
- elements.first.compile(subexpression_address, builder)
28
- accumulate_subexpression_result
29
- if elements.size > 1
30
- builder.if_ subexpression_success? do
31
- compile_sequence_elements(elements[1..-1])
32
- end
33
- end
34
- end
35
-
36
- def sequence_element_accessor_module
37
- @sequence_element_accessor_module ||= SequenceElementAccessorModule.new(sequence_elements)
38
- end
39
-
40
- def sequence_element_accessor_module_name
41
- sequence_element_accessor_module.module_name
42
- end
43
- end
44
-
45
- class SequenceElementAccessorModule
46
- include InlineModuleMixin
47
- attr_reader :sequence_elements
48
-
49
- def initialize(sequence_elements)
50
- @sequence_elements = sequence_elements
51
- end
52
-
53
- def compile(index, builder, rule)
54
- super
55
- builder.module_declaration(module_name) do
56
- sequence_elements.each_with_index do |element, index|
57
- if element.label_name
58
- builder.method_declaration(element.label_name) do
59
- builder << "elements[#{index}]"
60
- end
61
- builder.newline unless index == sequence_elements.size - 1
62
- end
63
- end
64
- end
65
- end
66
- end
67
- end
68
- end
@@ -1,20 +0,0 @@
1
- module Treetop
2
- module Compiler
3
- class Terminal < AtomicExpression
4
- def compile(address, builder, parent_expression = nil)
5
- super
6
- string_length = eval(text_value).length
7
-
8
- builder.if__ "has_terminal?(#{text_value}, false, index)" do
9
- assign_result "instantiate_node(#{node_class_name},input, index...(index + #{string_length}))"
10
- extend_result_with_inline_module
11
- builder << "@index += #{string_length}"
12
- end
13
- builder.else_ do
14
- builder << "terminal_parse_failure(#{text_value})"
15
- assign_result 'nil'
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,9 +0,0 @@
1
- module Treetop
2
- module Compiler
3
- class TransientPrefix < ParsingExpression
4
- def compile(address, builder, parent_expression)
5
- parent_expression.prefixed_expression.compile(address, builder)
6
- end
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module Treetop
2
- module Compiler
3
- class TreetopFile < Runtime::SyntaxNode
4
- def compile
5
- (elements.map {|elt| elt.compile}).join
6
- end
7
- end
8
- end
9
- end
@@ -1,113 +0,0 @@
1
- module Treetop
2
- module Compiler
3
- class RubyBuilder
4
-
5
- attr_reader :level, :address_space, :ruby
6
-
7
- def initialize
8
- @level = 0
9
- @address_space = LexicalAddressSpace.new
10
- @ruby = ""
11
- end
12
-
13
- def <<(ruby_line)
14
- return if ruby_line.blank?
15
- ruby << ruby_line.tabto(level) << "\n"
16
- end
17
-
18
- def newline
19
- ruby << "\n"
20
- end
21
-
22
- def indented(depth = 2)
23
- self.in(depth)
24
- yield
25
- self.out(depth)
26
- end
27
-
28
- def class_declaration(name, &block)
29
- self << "class #{name}"
30
- indented(&block)
31
- self << "end"
32
- end
33
-
34
- def module_declaration(name, &block)
35
- self << "module #{name}"
36
- indented(&block)
37
- self << "end"
38
- end
39
-
40
- def method_declaration(name, &block)
41
- self << "def #{name}"
42
- indented(&block)
43
- self << "end"
44
- end
45
-
46
- def assign(left, right)
47
- if left.instance_of? Array
48
- self << "#{left.join(', ')} = #{right.join(', ')}"
49
- else
50
- self << "#{left} = #{right}"
51
- end
52
- end
53
-
54
- def extend(var, module_name)
55
- self << "#{var}.extend(#{module_name})"
56
- end
57
-
58
- def accumulate(left, right)
59
- self << "#{left} << #{right}"
60
- end
61
-
62
- def if__(condition, &block)
63
- self << "if #{condition}"
64
- indented(&block)
65
- end
66
-
67
- def if_(condition, &block)
68
- if__(condition, &block)
69
- self << 'end'
70
- end
71
-
72
- def else_(&block)
73
- self << 'else'
74
- indented(&block)
75
- self << 'end'
76
- end
77
-
78
- def loop(&block)
79
- self << 'loop do'
80
- indented(&block)
81
- self << 'end'
82
- end
83
-
84
- def break
85
- self << 'break'
86
- end
87
-
88
- def in(depth = 2)
89
- @level += depth
90
- self
91
- end
92
-
93
- def out(depth = 2)
94
- @level -= depth
95
- self
96
- end
97
-
98
- def next_address
99
- address_space.next_address
100
- end
101
-
102
- def reset_addresses
103
- address_space.reset_addresses
104
- end
105
-
106
- private
107
-
108
- def indent
109
- " " * level
110
- end
111
- end
112
- end
113
- end
@@ -1,2 +0,0 @@
1
- dir = File.dirname(__FILE__)
2
- require "#{dir}/ruby_extensions/string"
@@ -1,42 +0,0 @@
1
- class String
2
- def column_of(index)
3
- return 1 if index == 0
4
- newline_index = rindex("\n", index - 1)
5
- if newline_index
6
- index - newline_index
7
- else
8
- index + 1
9
- end
10
- end
11
-
12
- def line_of(index)
13
- self[0...index].count("\n") + 1
14
- end
15
-
16
- unless method_defined?(:blank?)
17
- def blank?
18
- self == ""
19
- end
20
- end
21
-
22
- # The following methods are lifted from Facets 2.0.2
23
- def tabto(n)
24
- if self =~ /^( *)\S/
25
- indent(n - $1.length)
26
- else
27
- self
28
- end
29
- end
30
-
31
- def indent(n)
32
- if n >= 0
33
- gsub(/^/, ' ' * n)
34
- else
35
- gsub(/^ {0,#{-n}}/, "")
36
- end
37
- end
38
-
39
- def treetop_camelize
40
- to_s.gsub(/\/(.?)/){ "::" + $1.upcase }.gsub(/(^|_)(.)/){ $2.upcase }
41
- end
42
- end
@@ -1,5 +0,0 @@
1
- dir = File.dirname(__FILE__)
2
- require "#{dir}/runtime/compiled_parser"
3
- require "#{dir}/runtime/syntax_node"
4
- require "#{dir}/runtime/terminal_parse_failure"
5
- require "#{dir}/runtime/interval_skip_list"
@@ -1,105 +0,0 @@
1
- module Treetop
2
- module Runtime
3
- class CompiledParser
4
- include Treetop::Runtime
5
-
6
- attr_reader :input, :index, :terminal_failures, :max_terminal_failure_index
7
- attr_writer :root
8
- attr_accessor :consume_all_input
9
- alias :consume_all_input? :consume_all_input
10
-
11
- def initialize
12
- self.consume_all_input = true
13
- end
14
-
15
- def parse(input, options = {})
16
- prepare_to_parse(input)
17
- @index = options[:index] if options[:index]
18
- result = send("_nt_#{root}")
19
- return nil if (consume_all_input? && index != input.size)
20
- return result
21
- end
22
-
23
- def failure_index
24
- max_terminal_failure_index
25
- end
26
-
27
- def failure_line
28
- terminal_failures && input.line_of(failure_index)
29
- end
30
-
31
- def failure_column
32
- terminal_failures && input.column_of(failure_index)
33
- end
34
-
35
- def failure_reason
36
- return nil unless (tf = terminal_failures) && tf.size > 0
37
- "Expected " +
38
- (tf.size == 1 ?
39
- tf[0].expected_string :
40
- "one of #{tf.map{|f| f.expected_string}.uniq*', '}"
41
- ) +
42
- " at line #{failure_line}, column #{failure_column} (byte #{failure_index+1})" +
43
- " after #{input[index...failure_index]}"
44
- end
45
-
46
-
47
- protected
48
-
49
- attr_reader :node_cache, :input_length
50
- attr_writer :index
51
-
52
- def prepare_to_parse(input)
53
- @input = input
54
- @input_length = input.length
55
- reset_index
56
- @node_cache = Hash.new {|hash, key| hash[key] = Hash.new}
57
- @regexps = {}
58
- @terminal_failures = []
59
- @max_terminal_failure_index = 0
60
- end
61
-
62
- def reset_index
63
- @index = 0
64
- end
65
-
66
- def parse_anything(node_class = SyntaxNode, inline_module = nil)
67
- if index < input.length
68
- result = instantiate_node(node_class,input, index...(index + 1))
69
- result.extend(inline_module) if inline_module
70
- @index += 1
71
- result
72
- else
73
- terminal_parse_failure("any character")
74
- end
75
- end
76
-
77
- def instantiate_node(node_type,*args)
78
- if node_type.respond_to? :new
79
- node_type.new(*args)
80
- else
81
- SyntaxNode.new(*args).extend(node_type)
82
- end
83
- end
84
-
85
- def has_terminal?(terminal, regex, index)
86
- if regex
87
- rx = @regexps[terminal] ||= Regexp.new(terminal)
88
- input.index(rx, index) == index
89
- else
90
- input[index, terminal.size] == terminal
91
- end
92
- end
93
-
94
- def terminal_parse_failure(expected_string)
95
- return nil if index < max_terminal_failure_index
96
- if index > max_terminal_failure_index
97
- @max_terminal_failure_index = index
98
- @terminal_failures = []
99
- end
100
- terminal_failures << TerminalParseFailure.new(index, expected_string)
101
- return nil
102
- end
103
- end
104
- end
105
- end
@@ -1,4 +0,0 @@
1
- dir = File.dirname(__FILE__)
2
- require "#{dir}/interval_skip_list/interval_skip_list.rb"
3
- require "#{dir}/interval_skip_list/head_node.rb"
4
- require "#{dir}/interval_skip_list/node.rb"
@@ -1,15 +0,0 @@
1
- class IntervalSkipList
2
- class HeadNode
3
- attr_reader :height, :forward, :forward_markers
4
-
5
- def initialize(height)
6
- @height = height
7
- @forward = Array.new(height, nil)
8
- @forward_markers = Array.new(height) {|i| []}
9
- end
10
-
11
- def top_level
12
- height - 1
13
- end
14
- end
15
- end
@@ -1,200 +0,0 @@
1
- class IntervalSkipList
2
- attr_reader :probability
3
-
4
- def initialize
5
- @head = HeadNode.new(max_height)
6
- @ranges = {}
7
- @probability = 0.5
8
- end
9
-
10
- def max_height
11
- 3
12
- end
13
-
14
- def empty?
15
- head.forward[0].nil?
16
- end
17
-
18
- def expire(range, length_change)
19
- expired_markers, first_node_after_range = overlapping(range)
20
- expired_markers.each { |marker| delete(marker) }
21
- first_node_after_range.propagate_length_change(length_change)
22
- end
23
-
24
- def overlapping(range)
25
- markers, first_node = containing_with_node(range.first)
26
-
27
- cur_node = first_node
28
- begin
29
- markers.concat(cur_node.forward_markers.flatten)
30
- cur_node = cur_node.forward[0]
31
- end while cur_node.key < range.last
32
-
33
- return markers.uniq, cur_node
34
- end
35
-
36
- def containing(n)
37
- containing_with_node(n).first
38
- end
39
-
40
- def insert(range, marker)
41
- ranges[marker] = range
42
- first_node = insert_node(range.first)
43
- first_node.endpoint_of.push(marker)
44
- last_node = insert_node(range.last)
45
- last_node.endpoint_of.push(marker)
46
-
47
- cur_node = first_node
48
- cur_level = first_node.top_level
49
- while next_node_at_level_inside_range?(cur_node, cur_level, range)
50
- while can_ascend_from?(cur_node, cur_level) && next_node_at_level_inside_range?(cur_node, cur_level + 1, range)
51
- cur_level += 1
52
- end
53
- cur_node = mark_forward_path_at_level(cur_node, cur_level, marker)
54
- end
55
-
56
- while node_inside_range?(cur_node, range)
57
- while can_descend_from?(cur_level) && next_node_at_level_outside_range?(cur_node, cur_level, range)
58
- cur_level -= 1
59
- end
60
- cur_node = mark_forward_path_at_level(cur_node, cur_level, marker)
61
- end
62
- end
63
-
64
- def delete(marker)
65
- range = ranges[marker]
66
- path_to_first_node = make_path
67
- first_node = find(range.first, path_to_first_node)
68
-
69
- cur_node = first_node
70
- cur_level = first_node.top_level
71
- while next_node_at_level_inside_range?(cur_node, cur_level, range)
72
- while can_ascend_from?(cur_node, cur_level) && next_node_at_level_inside_range?(cur_node, cur_level + 1, range)
73
- cur_level += 1
74
- end
75
- cur_node = unmark_forward_path_at_level(cur_node, cur_level, marker)
76
- end
77
-
78
- while node_inside_range?(cur_node, range)
79
- while can_descend_from?(cur_level) && next_node_at_level_outside_range?(cur_node, cur_level, range)
80
- cur_level -= 1
81
- end
82
- cur_node = unmark_forward_path_at_level(cur_node, cur_level, marker)
83
- end
84
- last_node = cur_node
85
-
86
- first_node.endpoint_of.delete(marker)
87
- if first_node.endpoint_of.empty?
88
- first_node.delete(path_to_first_node)
89
- end
90
-
91
- last_node.endpoint_of.delete(marker)
92
- if last_node.endpoint_of.empty?
93
- path_to_last_node = make_path
94
- find(range.last, path_to_last_node)
95
- last_node.delete(path_to_last_node)
96
- end
97
- end
98
-
99
- protected
100
- attr_reader :head, :ranges
101
-
102
- def insert_node(key)
103
- path = make_path
104
- found_node = find(key, path)
105
- if found_node && found_node.key == key
106
- return found_node
107
- else
108
- return Node.new(key, next_node_height, path)
109
- end
110
- end
111
-
112
- def containing_with_node(n)
113
- containing = []
114
- cur_node = head
115
- (max_height - 1).downto(0) do |cur_level|
116
- while (next_node = cur_node.forward[cur_level]) && next_node.key <= n
117
- cur_node = next_node
118
- if cur_node.key == n
119
- return containing + (cur_node.markers - cur_node.endpoint_of), cur_node
120
- end
121
- end
122
- containing.concat(cur_node.forward_markers[cur_level])
123
- end
124
-
125
- return containing, cur_node
126
- end
127
-
128
- def delete_node(key)
129
- path = make_path
130
- found_node = find(key, path)
131
- found_node.delete(path) if found_node.key == key
132
- end
133
-
134
- def find(key, path)
135
- cur_node = head
136
- (max_height - 1).downto(0) do |cur_level|
137
- while (next_node = cur_node.forward[cur_level]) && next_node.key < key
138
- cur_node = next_node
139
- end
140
- path[cur_level] = cur_node
141
- end
142
- cur_node.forward[0]
143
- end
144
-
145
- def make_path
146
- Array.new(max_height, nil)
147
- end
148
-
149
- def next_node_height
150
- height = 1
151
- while rand < probability && height < max_height
152
- height += 1
153
- end
154
- height
155
- end
156
-
157
- def can_ascend_from?(node, level)
158
- level < node.top_level
159
- end
160
-
161
- def can_descend_from?(level)
162
- level > 0
163
- end
164
-
165
- def node_inside_range?(node, range)
166
- node.key < range.last
167
- end
168
-
169
- def next_node_at_level_inside_range?(node, level, range)
170
- node.forward[level] && node.forward[level].key <= range.last
171
- end
172
-
173
- def next_node_at_level_outside_range?(node, level, range)
174
- (node.forward[level].nil? || node.forward[level].key > range.last)
175
- end
176
-
177
- def mark_forward_path_at_level(node, level, marker)
178
- node.forward_markers[level].push(marker)
179
- next_node = node.forward[level]
180
- next_node.markers.push(marker)
181
- node = next_node
182
- end
183
-
184
- def unmark_forward_path_at_level(node, level, marker)
185
- node.forward_markers[level].delete(marker)
186
- next_node = node.forward[level]
187
- next_node.markers.delete(marker)
188
- node = next_node
189
- end
190
-
191
- def nodes
192
- nodes = []
193
- cur_node = head.forward[0]
194
- until cur_node.nil?
195
- nodes << cur_node
196
- cur_node = cur_node.forward[0]
197
- end
198
- nodes
199
- end
200
- end