hyperdoc 0.1.0 → 0.1.1
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/README.md +6 -2
- data/{test/check_all.rb → checks/all.rb} +0 -0
- data/checks/core/check_array.rb +154 -0
- data/checks/core/check_document.rb +51 -0
- data/checks/core/check_hash.rb +50 -0
- data/{test → checks}/setup.rb +2 -0
- data/hyperdoc.gemspec +2 -2
- data/library/hyperdoc.rb +21 -0
- data/library/hyperdoc/{link.rb → agent.rb} +0 -0
- data/library/hyperdoc/array.rb +158 -0
- data/library/hyperdoc/box.rb +5 -0
- data/library/hyperdoc/{nop.rb → couch/database.rb} +0 -0
- data/library/hyperdoc/{schema.rb → couch/document.rb} +0 -0
- data/library/hyperdoc/{selector.rb → couch/view.rb} +0 -0
- data/library/hyperdoc/document.rb +68 -0
- data/library/hyperdoc/factory.rb +44 -0
- data/library/hyperdoc/hash.rb +69 -0
- data/library/hyperdoc/meta.rb +14 -0
- data/library/hyperdoc/type.rb +86 -0
- data/rakefile +6 -13
- metadata +22 -16
- data/library/hyperdoc/value.rb +0 -0
data/README.md
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
hyperdoc
|
2
2
|
========
|
3
3
|
|
4
|
-
hypertextual documents using plain old data structures
|
4
|
+
This library helps build hypertextual documents using plain old data structures which are designed for use in a REST friendly ecosystem. I'll be adding more here as I port the ideas over from the old repo. This is also part of a the upcoming open sourced General Assembly platform.
|
5
|
+
|
6
|
+
NOTE: This release is completely unoptimized! Work is being done to reduce the complexity of the behaviors Hyperdoc's exhibit before things are tuned.
|
5
7
|
|
6
8
|
License
|
7
9
|
-------
|
8
10
|
|
11
|
+
Thanks goes out to constantcontact/dash for allowing me to open source an *very early* prototype of these ideas. While it has evolved quite a bit since then, the core ideas have remained the same.
|
12
|
+
|
9
13
|
While it might be controversial, I'm going to give CC a shot for code. The [CC FAQ](http://wiki.creativecommons.org/Frequently_Asked_Questions#Can_I_apply_a_Creative_Commons_license_to_software.3F) does not usually recommend it, though their reasons seem based around problems that a similar MIT style license does not address either. GPL compatibility is not a concern here either since I'd rather not see this relicensed under a more viral contract.
|
10
14
|
|
11
|
-
<a rel="license" href="http://creativecommons.org/licenses/by/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by/3.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">hyperdoc</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="http://generalassemb.ly/" property="cc:attributionName" rel="cc:attributionURL">General Assembly</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 Unported License</a>.
|
15
|
+
<a rel="license" href="http://creativecommons.org/licenses/by/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by/3.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">hyperdoc</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="http://generalassemb.ly/" property="cc:attributionName" rel="cc:attributionURL">General Assembly</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 Unported License</a>.
|
File without changes
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require_relative '../setup'
|
2
|
+
|
3
|
+
class ArrayTest < TestCase
|
4
|
+
|
5
|
+
def test_compact
|
6
|
+
obj = Hyperdoc.new('arr' => [1, nil, 2, nil, 3])
|
7
|
+
arr = obj.arr
|
8
|
+
compacted = arr.compact
|
9
|
+
assert_equal [1,2,3], compacted.meta.value
|
10
|
+
assert_equal arr.meta.parent, compacted.meta.parent
|
11
|
+
assert_equal arr.meta.key, compacted.meta.key
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_compact_bang
|
15
|
+
arr = Hyperdoc.new([nil, 1, Hyperdoc.new(nil), 2, nil])
|
16
|
+
assert_equal arr, arr.compact!
|
17
|
+
assert_equal [1,2], arr.meta.value
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_each
|
21
|
+
arr = Hyperdoc.new([{'a' => 'b'}, [3, 4]])
|
22
|
+
arr.each do |obj|
|
23
|
+
assert Hyperdoc::Type === obj
|
24
|
+
end
|
25
|
+
arr = Hyperdoc.new([0, 1])
|
26
|
+
arr.each do |obj|
|
27
|
+
assert !(Hyperdoc::Type === obj)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_first
|
32
|
+
arr = Hyperdoc.new([{'a' => 42}])
|
33
|
+
assert_equal 42, arr.first.a
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_last
|
37
|
+
arr = Hyperdoc.new([0, 1, 2, 42])
|
38
|
+
assert_equal 42, arr.last
|
39
|
+
arr = Hyperdoc.new([0, 1, {}])
|
40
|
+
assert_equal 2, arr.last.meta.key
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_map
|
44
|
+
arr = Hyperdoc.new([1,2,3])
|
45
|
+
assert_equal [-1,-2,-3], arr.map {|x| -x}.meta.value
|
46
|
+
arr = Hyperdoc.new([{'a' => 'b'}])
|
47
|
+
assert_equal ['a=b'], arr.map {|x| "a=#{x.a}"}.meta.value
|
48
|
+
obj = Hyperdoc.new({'arr' => [1,2,3]})
|
49
|
+
mapped_array = obj.arr.map {|x| -x}
|
50
|
+
assert_equal obj, mapped_array.meta.parent.box
|
51
|
+
assert_equal 'arr', mapped_array.meta.key
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_map_bang
|
55
|
+
arr = Hyperdoc.new([{'a' => 1}, {'a' => 2}])
|
56
|
+
assert_equal arr, arr.map! {|x| x.a}
|
57
|
+
assert_equal [1,2], arr.meta.value
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_push
|
61
|
+
arr = Hyperdoc.new([1,2,3])
|
62
|
+
arr.push(4)
|
63
|
+
arr << 5 << 6
|
64
|
+
assert_equal [1,2,3,4,5,6], arr.meta.value
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_reduce
|
68
|
+
arr = Hyperdoc.new([0,1,2])
|
69
|
+
assert_equal 3, arr.reduce(:+)
|
70
|
+
assert_equal 3, arr.inject(:+)
|
71
|
+
assert_equal 0, arr.reduce(-3, :+)
|
72
|
+
assert_equal 3, arr.reduce {|x,y| x + y}
|
73
|
+
assert_equal 0, arr.reduce(-3) {|x,y| x + y}
|
74
|
+
assert_raise(ArgumentError) {arr.inject}
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_reject
|
78
|
+
obj = Hyperdoc.new('arr' => (1..10).to_a)
|
79
|
+
arr = obj.arr
|
80
|
+
odds = arr.reject {|x| x % 2 == 0}
|
81
|
+
assert_equal [1,3,5,7,9], odds.meta.value
|
82
|
+
assert_equal arr.meta.parent, odds.meta.parent
|
83
|
+
assert_equal arr.meta.key, odds.meta.key
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_reject_bang
|
87
|
+
arr = Hyperdoc.new([1,2,3,4])
|
88
|
+
assert_equal arr, arr.reject! {|x| x % 2 == 0}
|
89
|
+
assert_equal [1,3], arr.meta.value
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_select
|
93
|
+
obj = Hyperdoc.new('arr' => (1..10).to_a)
|
94
|
+
arr = obj.arr
|
95
|
+
evens = arr.select {|x| x % 2 == 0}
|
96
|
+
assert_equal [2,4,6,8,10], evens.meta.value
|
97
|
+
assert_equal arr.meta.parent, evens.meta.parent
|
98
|
+
assert_equal arr.meta.key, evens.meta.key
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_select_bang
|
102
|
+
arr = Hyperdoc.new([1,2,3,4])
|
103
|
+
assert_equal arr, arr.select! {|x| x % 2 == 0}
|
104
|
+
assert_equal [2,4], arr.meta.value
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_sort
|
108
|
+
obj = Hyperdoc.new('arr' => [1,3,2,5,4])
|
109
|
+
arr = obj.arr
|
110
|
+
sorted = arr.sort
|
111
|
+
assert_equal [1,2,3,4,5], sorted.meta.value
|
112
|
+
assert_equal arr.meta.parent, sorted.meta.parent
|
113
|
+
assert_equal arr.meta.key, sorted.meta.key
|
114
|
+
sorted = arr.sort {|x, y| y <=> x}
|
115
|
+
assert_equal [5,4,3,2,1], sorted.meta.value
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_sort_bang
|
119
|
+
arr = Hyperdoc.new([3,4,1,2])
|
120
|
+
assert_equal arr, arr.sort!
|
121
|
+
assert_equal [1,2,3,4], arr.meta.value
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_sort_by
|
125
|
+
obj = Hyperdoc.new('arr' => [1,2,3,4])
|
126
|
+
arr = obj.arr
|
127
|
+
sorted = arr.sort_by {|x| -x}
|
128
|
+
assert_equal [4,3,2,1], sorted.meta.value
|
129
|
+
assert_equal arr.meta.parent, sorted.meta.parent
|
130
|
+
assert_equal arr.meta.key, sorted.meta.key
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_sort_by_bang
|
134
|
+
arr = Hyperdoc.new([1,2,3,4])
|
135
|
+
assert_equal arr, arr.sort_by! {|x| -x}
|
136
|
+
assert_equal [4,3,2,1], arr.meta.value
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_uniq
|
140
|
+
obj = Hyperdoc.new('arr' => [1,1,2,2,3,3])
|
141
|
+
arr = obj.arr
|
142
|
+
uniq = arr.uniq
|
143
|
+
assert_equal [1,2,3], uniq.meta.value
|
144
|
+
assert_equal arr.meta.parent, uniq.meta.parent
|
145
|
+
assert_equal arr.meta.key, uniq.meta.key
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_uniq_bang
|
149
|
+
arr = Hyperdoc.new([1, 1, 2, 1, 1])
|
150
|
+
assert_equal arr, arr.uniq!
|
151
|
+
assert_equal [1,2], arr.meta.value
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require_relative '../setup'
|
2
|
+
|
3
|
+
class BoxTest < TestCase
|
4
|
+
|
5
|
+
def test_match_delegation
|
6
|
+
assert Hyperdoc.new('abc') =~ /abc/
|
7
|
+
assert Hyperdoc.new('abc') !~ /xyz/
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_to_s_delegation
|
11
|
+
assert_equal '?'.to_s, Hyperdoc.new('?').to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_comparison
|
15
|
+
assert Hyperdoc.new(a: 42) == {a: 42}
|
16
|
+
assert Hyperdoc.new(42) > 41
|
17
|
+
assert_equal 0, Hyperdoc.new(42) <=> Hyperdoc.new(42)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_value_extraction
|
21
|
+
assert_equal [42], Hyperdoc.new([42]).meta.value
|
22
|
+
assert_equal 42, Hyperdoc.new(42)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
class CustomBaseTest < TestCase
|
28
|
+
|
29
|
+
class X
|
30
|
+
include Hyperdoc::Type
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_hash_construction
|
34
|
+
obj = X.new(a: 42)
|
35
|
+
assert Hyperdoc::Type === obj
|
36
|
+
assert_equal 42, obj.a
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_array_construciton
|
40
|
+
obj = X.new([42])
|
41
|
+
assert Hyperdoc::Type === obj
|
42
|
+
assert_equal 42, obj.first
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_value_construction
|
46
|
+
assert_equal 42, X.new(42)
|
47
|
+
assert_equal nil, X.new(nil)
|
48
|
+
assert_equal "42", X.new("42")
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative '../setup'
|
2
|
+
|
3
|
+
class AccessBehaviorTest < TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@hash = Hyperdoc.new('a' => 42, b: 43)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_accessor_synthesis
|
10
|
+
assert @hash.a == 42
|
11
|
+
assert @hash.respond_to?(:a)
|
12
|
+
assert @hash.b == 43
|
13
|
+
assert @hash.respond_to?(:b)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_missing_accessor_synthesis
|
17
|
+
assert @hash.blahblah.nil?
|
18
|
+
assert @hash.respond_to?(:blahblah)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_query_synthesis
|
22
|
+
assert @hash.a?
|
23
|
+
assert @hash.respond_to?(:a?)
|
24
|
+
assert @hash.b?
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_missing_query_synthesis
|
28
|
+
assert !@hash.blahblah?
|
29
|
+
assert @hash.respond_to?(:blahblah?)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_assignment_synthesis
|
33
|
+
@hash.answer = 42
|
34
|
+
assert_equal 42, @hash.answer
|
35
|
+
assert @hash.respond_to?(:answer=)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
class BoxingBehaviorTest < TestCase
|
41
|
+
|
42
|
+
def test_assignment_should_unbox
|
43
|
+
hash = {'b' => 42}
|
44
|
+
object = Hyperdoc.new({})
|
45
|
+
object.a = Hyperdoc.new(hash)
|
46
|
+
object.a = object.a # assign a boxed value which should become unboxed
|
47
|
+
assert_equal hash.class, object.a.meta.value.class
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
data/{test → checks}/setup.rb
RENAMED
data/hyperdoc.gemspec
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
Gem::Specification.new do |gem|
|
2
2
|
gem.name = 'hyperdoc'
|
3
|
-
gem.version = '0.1.
|
3
|
+
gem.version = '0.1.1'
|
4
4
|
gem.date = '2012-05-18'
|
5
5
|
gem.summary = "hypertextual documents using plain old data structures"
|
6
|
-
gem.authors = ['strmpnk (Brian Mitchell)', 'John Paul Ashenfelter']
|
6
|
+
gem.authors = ['strmpnk (Brian Mitchell)', 'John Paul Ashenfelter', 'Robert Gleeson']
|
7
7
|
gem.email = 'brian@generalassemb.ly'
|
8
8
|
gem.homepage = 'https://github.com/generalassembly/hyperdoc'
|
9
9
|
gem.require_paths = %w[library]
|
data/library/hyperdoc.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Hyperdoc
|
2
|
+
|
3
|
+
# value model
|
4
|
+
autoload :Array, 'hyperdoc/array'
|
5
|
+
autoload :Box, 'hyperdoc/box'
|
6
|
+
autoload :Factory, 'hyperdoc/factory'
|
7
|
+
autoload :Hash, 'hyperdoc/hash'
|
8
|
+
autoload :Type, 'hyperdoc/type'
|
9
|
+
|
10
|
+
# document model
|
11
|
+
autoload :Agent, 'hyperdoc/agent'
|
12
|
+
autoload :Meta, 'hyperdoc/meta'
|
13
|
+
|
14
|
+
# drivers
|
15
|
+
autoload :Couch, 'hyperdoc/couch'
|
16
|
+
|
17
|
+
def self.new(value)
|
18
|
+
Hyperdoc::Box.new(value)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
File without changes
|
data/library/hyperdoc/array.rb
CHANGED
@@ -0,0 +1,158 @@
|
|
1
|
+
module Hyperdoc::Array
|
2
|
+
|
3
|
+
def [](key)
|
4
|
+
box(key, meta.value[key])
|
5
|
+
end
|
6
|
+
|
7
|
+
def []=(key, value)
|
8
|
+
value = unbox(value)
|
9
|
+
meta.value[key] = unbox(value)
|
10
|
+
end
|
11
|
+
|
12
|
+
def compact
|
13
|
+
rebox meta.value.compact
|
14
|
+
end
|
15
|
+
|
16
|
+
def compact!
|
17
|
+
meta.value.reject! {|x| x.nil?}
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def each
|
22
|
+
meta.value.each_with_index do |value, i|
|
23
|
+
yield box(i, value)
|
24
|
+
end
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def first
|
29
|
+
box(0, meta.value.first)
|
30
|
+
end
|
31
|
+
|
32
|
+
def last
|
33
|
+
box(meta.value.size - 1, meta.value.last)
|
34
|
+
end
|
35
|
+
|
36
|
+
def map
|
37
|
+
arr = []
|
38
|
+
each do |box|
|
39
|
+
arr << unbox(yield(box))
|
40
|
+
end
|
41
|
+
rebox(arr)
|
42
|
+
end
|
43
|
+
|
44
|
+
def map!
|
45
|
+
meta.value.map!.with_index do |x, i|
|
46
|
+
unbox(yield box(i, x))
|
47
|
+
end
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
def push(item)
|
52
|
+
meta.value.push unbox(item)
|
53
|
+
self
|
54
|
+
end
|
55
|
+
alias_method :<<, :push
|
56
|
+
|
57
|
+
def reduce(*args, &block)
|
58
|
+
case args.size
|
59
|
+
when 0
|
60
|
+
initial = false
|
61
|
+
block_given? or raise ArgumentError,
|
62
|
+
"no block given"
|
63
|
+
when 1
|
64
|
+
initial = block_given?
|
65
|
+
block = args[0].to_proc unless initial
|
66
|
+
when 2
|
67
|
+
initial = true
|
68
|
+
block = args[1].to_proc
|
69
|
+
else
|
70
|
+
raise ArgumentError,
|
71
|
+
"Too many arguments: #{args.size} for 0 to 2"
|
72
|
+
end
|
73
|
+
memo = initial ? args[0] : nil
|
74
|
+
meta.value.each_with_index do |value, i|
|
75
|
+
# set an initial memo on first loop unless we were passed one
|
76
|
+
memo = (!initial && i == 0) ?
|
77
|
+
box(i, value) :
|
78
|
+
block.call(memo, box(i, value))
|
79
|
+
end
|
80
|
+
memo
|
81
|
+
end
|
82
|
+
alias inject reduce
|
83
|
+
|
84
|
+
def reject
|
85
|
+
selected = meta.value.reject.with_index do |x, i|
|
86
|
+
yield box(i, x)
|
87
|
+
end
|
88
|
+
rebox(selected)
|
89
|
+
end
|
90
|
+
|
91
|
+
def reject!
|
92
|
+
meta.value.reject!.with_index do |x, i|
|
93
|
+
yield box(i, x)
|
94
|
+
end
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
def size
|
99
|
+
meta.value.size
|
100
|
+
end
|
101
|
+
|
102
|
+
def select
|
103
|
+
selected = meta.value.select.with_index do |x, i|
|
104
|
+
yield box(i, x)
|
105
|
+
end
|
106
|
+
rebox(selected)
|
107
|
+
end
|
108
|
+
|
109
|
+
def select!
|
110
|
+
meta.value.select!.with_index do |x, i|
|
111
|
+
yield box(i, x)
|
112
|
+
end
|
113
|
+
self
|
114
|
+
end
|
115
|
+
|
116
|
+
def sort
|
117
|
+
if block_given?
|
118
|
+
# box everything once and then sort the boxes
|
119
|
+
sorted = meta.value.map.with_index do |v, i|
|
120
|
+
box(i, v)
|
121
|
+
end.sort do |a,b|
|
122
|
+
yield a,b
|
123
|
+
end
|
124
|
+
else
|
125
|
+
sorted = meta.value.sort
|
126
|
+
end
|
127
|
+
rebox(sorted)
|
128
|
+
end
|
129
|
+
|
130
|
+
def sort!
|
131
|
+
meta.value.sort!
|
132
|
+
self
|
133
|
+
end
|
134
|
+
|
135
|
+
def sort_by
|
136
|
+
sorted = meta.value.sort_by.with_index do |x, i|
|
137
|
+
yield box(i, x)
|
138
|
+
end
|
139
|
+
rebox(sorted)
|
140
|
+
end
|
141
|
+
|
142
|
+
def sort_by!
|
143
|
+
meta.value.sort_by!.with_index do |x, i|
|
144
|
+
yield box(i, x)
|
145
|
+
end
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
149
|
+
def uniq
|
150
|
+
rebox meta.value.uniq
|
151
|
+
end
|
152
|
+
|
153
|
+
def uniq!
|
154
|
+
meta.value.uniq!
|
155
|
+
self
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
data/library/hyperdoc/box.rb
CHANGED
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class Hyperdoc::Document
|
2
|
+
include Comparable
|
3
|
+
include Hyperdoc::Generator
|
4
|
+
|
5
|
+
def self.generate(types)
|
6
|
+
return self if types.empty?
|
7
|
+
@cache[types]
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.inherited(subclass)
|
11
|
+
# inherit schema
|
12
|
+
# setup caches for subclass
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.inspect
|
16
|
+
return name if name
|
17
|
+
base = self
|
18
|
+
base = base.superclass until base.name
|
19
|
+
behaviors = ancestors[1..-1] - base.ancestors
|
20
|
+
behaviors.empty? ?
|
21
|
+
"#{base}":
|
22
|
+
"#{base}(#{behaviors.join(',')})"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.on(selectors)
|
26
|
+
selectors.each do |code, type|
|
27
|
+
schema.register(code, type)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
public
|
32
|
+
|
33
|
+
undef_method :=~
|
34
|
+
undef_method :nil?
|
35
|
+
undef_method :to_s
|
36
|
+
|
37
|
+
def <=>(other)
|
38
|
+
value <=> unbox(other)
|
39
|
+
end
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
key ?
|
43
|
+
"#<#{self.class.inxpect}##{full_path.join('.')}: #{value.inspect}>":
|
44
|
+
"#<#{self.class.inspect}: #{value.inspect}>"
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
attr_accessor :key, :parent, :schema
|
50
|
+
attr_reader :value
|
51
|
+
|
52
|
+
def box()
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(value)
|
57
|
+
@value = value
|
58
|
+
end
|
59
|
+
|
60
|
+
def rebox()
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
def unbox()
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Hyperdoc::Factory
|
2
|
+
|
3
|
+
def inspect
|
4
|
+
return name if name
|
5
|
+
base = self
|
6
|
+
base = base.superclass until base.name
|
7
|
+
behaviors = ancestors[1..-1] - base.ancestors
|
8
|
+
behaviors.empty? ?
|
9
|
+
"#{base}":
|
10
|
+
"#{base}(#{behaviors.join(',')})"
|
11
|
+
end
|
12
|
+
|
13
|
+
def new(value)
|
14
|
+
# NOTE: this is unoptimized. Specialization will get more complex
|
15
|
+
# once selectors are added back. We'll delay optimizing this till
|
16
|
+
# after that feature is complete.
|
17
|
+
sub = Class.new(self)
|
18
|
+
type = value_type(value)
|
19
|
+
return value if type.nil?
|
20
|
+
sub.class_eval do
|
21
|
+
include type
|
22
|
+
undef_method :=~
|
23
|
+
end
|
24
|
+
sub.allocate.tap {|inst|
|
25
|
+
inst.meta.value = inst.send(:unbox, value)
|
26
|
+
inst.meta.box = inst
|
27
|
+
yield inst if block_given?
|
28
|
+
inst.send(:initialize)}
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def value_type(value)
|
34
|
+
case value
|
35
|
+
when ::Hash
|
36
|
+
Hyperdoc::Hash
|
37
|
+
when ::Array
|
38
|
+
Hyperdoc::Array
|
39
|
+
else
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/library/hyperdoc/hash.rb
CHANGED
@@ -0,0 +1,69 @@
|
|
1
|
+
module Hyperdoc::Hash
|
2
|
+
|
3
|
+
def [](key)
|
4
|
+
if meta.value.has_key?(key)
|
5
|
+
# Check natural type
|
6
|
+
box(key, meta.value[key])
|
7
|
+
elsif String === key
|
8
|
+
# Check symbol form
|
9
|
+
sym_key = key.to_sym
|
10
|
+
box(key, meta.value[sym_key])
|
11
|
+
else
|
12
|
+
# Check string form
|
13
|
+
str_key = key.to_s
|
14
|
+
box(key, meta.value[str_key])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def []=(key, value)
|
19
|
+
str_key = key.to_s
|
20
|
+
sym_key = key.to_sym
|
21
|
+
if meta.value.has_key?(sym_key)
|
22
|
+
if meta.value.has_key?(str_key)
|
23
|
+
meta.value[key] = unbox(value)
|
24
|
+
else
|
25
|
+
meta.value[sym_key] = unbox(value)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
meta.value[str_key] = unbox(value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_key?(key)
|
33
|
+
return true if meta.value.has_key?(key)
|
34
|
+
if String === key
|
35
|
+
meta.value.has_key?(key.to_sym)
|
36
|
+
else
|
37
|
+
meta.value.has_key?(key.to_s)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def access_call(symbol, key)
|
44
|
+
cached_call(symbol) {box(key, self[key])}
|
45
|
+
end
|
46
|
+
|
47
|
+
def assign_call(symbol, key)
|
48
|
+
cached_call(symbol) {|v| self[key] = v}
|
49
|
+
end
|
50
|
+
|
51
|
+
def method_missing(symbol, *args, &blk)
|
52
|
+
case symbol
|
53
|
+
when /(.*)=$/
|
54
|
+
key = $1
|
55
|
+
assign_call(symbol, key).call(*args, &blk)
|
56
|
+
when /(.*)\?$/
|
57
|
+
key = $1
|
58
|
+
query_call(symbol, key).call(*args, &blk)
|
59
|
+
else
|
60
|
+
key = symbol.to_s
|
61
|
+
access_call(symbol, key).call(*args, &blk)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def query_call(symbol, key)
|
66
|
+
cached_call(symbol) {has_key?(key) && !!box(key, self[key])}
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
data/library/hyperdoc/meta.rb
CHANGED
@@ -0,0 +1,86 @@
|
|
1
|
+
=begin
|
2
|
+
# Overview
|
3
|
+
|
4
|
+
Hyperdoc::Type is included in classes which intend on constructing
|
5
|
+
document instances. It transforms the new() interface into a sort of
|
6
|
+
factory which generates a class with the appropriate sort of
|
7
|
+
combination of modules based on what it's wrapping. This is don't
|
8
|
+
rather than subclassing for precisely that sort of late-bound behavior.
|
9
|
+
|
10
|
+
## Why Hyperdoc::Type and not some other name?
|
11
|
+
|
12
|
+
While it was originally going to be implemented directly on the
|
13
|
+
Hyperdoc module itself, this was a problem for constant lookup since
|
14
|
+
Hyperdoc implements many common constant names like Array and Hash, which
|
15
|
+
leads to a sort of ambiguity. This protects us somewhat by not creating
|
16
|
+
unintended ambiguity for those that include Hyperdoc::Type.
|
17
|
+
|
18
|
+
Type itself was chosen because it helps describe what it is. It's a sort of
|
19
|
+
Hyperdoc and will read well: Hyperdoc::Type === … Though we'll probably add
|
20
|
+
a simple implementation for Hyperdoc.=== which will delegate to
|
21
|
+
Hyperdoc::Type
|
22
|
+
|
23
|
+
=end
|
24
|
+
|
25
|
+
module Hyperdoc::Type
|
26
|
+
include Comparable
|
27
|
+
|
28
|
+
def self.append_features(_class)
|
29
|
+
Class === _class or raise ArgumentError,
|
30
|
+
"Hyperdoc::Type can only be included directly into a class, not a module"
|
31
|
+
super
|
32
|
+
_class.extend Hyperdoc::Factory
|
33
|
+
end
|
34
|
+
|
35
|
+
public
|
36
|
+
|
37
|
+
def <=>(other)
|
38
|
+
meta.value <=> unbox(other)
|
39
|
+
end
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
meta.path ?
|
43
|
+
"#<#{self.class.inspect}##{meta.path}: #{meta.inspect}>":
|
44
|
+
"#<#{self.class.inspect}: #{meta.inspect}>"
|
45
|
+
end
|
46
|
+
|
47
|
+
def meta
|
48
|
+
@hyperdoc_meta ||= Hyperdoc::Meta.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s(*a)
|
52
|
+
meta.value.to_s(*a)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def box(key, value)
|
58
|
+
Hyperdoc::Box.new(value) { |box|
|
59
|
+
box.meta.key = key
|
60
|
+
box.meta.parent = meta
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def rebox(value)
|
65
|
+
self.dup.tap { |box|
|
66
|
+
box.meta.value = value
|
67
|
+
box.meta.box = box
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def unbox(object)
|
72
|
+
Hyperdoc::Type === object ? unbox(object.meta.value) : object
|
73
|
+
end
|
74
|
+
|
75
|
+
def cached_call(symbol, &proc)
|
76
|
+
unless self.respond_to?(symbol, true)
|
77
|
+
self.class.class_eval {define_method(symbol, &proc)}
|
78
|
+
end
|
79
|
+
proc
|
80
|
+
end
|
81
|
+
|
82
|
+
def scrub_call(symbol)
|
83
|
+
self.class.class_eval {undef_method symbol}
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
data/rakefile
CHANGED
@@ -1,23 +1,16 @@
|
|
1
1
|
task default: [:test, :build]
|
2
2
|
|
3
|
-
task compile: 'lib/dash/selector.kpeg.rb'
|
4
|
-
|
5
3
|
desc "check tests"
|
6
|
-
task :test
|
7
|
-
ruby ENV['ONLY'] || '
|
4
|
+
task :test do
|
5
|
+
ruby ENV['ONLY'] || 'checks/all.rb'
|
8
6
|
end
|
9
7
|
|
10
8
|
desc "build dash gem"
|
11
|
-
task :build
|
12
|
-
sh 'gem build
|
9
|
+
task :build do
|
10
|
+
sh 'gem build hyperdoc.gemspec'
|
13
11
|
end
|
14
12
|
|
15
13
|
desc "clean build artifacts"
|
16
14
|
task :clean do
|
17
|
-
rm '
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
file 'lib/dash/selector.kpeg.rb' => 'lib/dash/selector.kpeg' do
|
22
|
-
sh "kpeg --stand-alone --force --output lib/dash/selector.kpeg.rb lib/dash/selector.kpeg"
|
23
|
-
end
|
15
|
+
rm 'hyperdoc-*.gem'
|
16
|
+
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hyperdoc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- strmpnk (Brian Mitchell)
|
9
9
|
- John Paul Ashenfelter
|
10
|
+
- Robert Gleeson
|
10
11
|
autorequire:
|
11
12
|
bindir: bin
|
12
13
|
cert_chain: []
|
@@ -14,7 +15,7 @@ date: 2012-05-18 00:00:00.000000000 Z
|
|
14
15
|
dependencies:
|
15
16
|
- !ruby/object:Gem::Dependency
|
16
17
|
name: celluloid
|
17
|
-
requirement: &
|
18
|
+
requirement: &70245880712420 !ruby/object:Gem::Requirement
|
18
19
|
none: false
|
19
20
|
requirements:
|
20
21
|
- - ! '>='
|
@@ -22,10 +23,10 @@ dependencies:
|
|
22
23
|
version: '0'
|
23
24
|
type: :runtime
|
24
25
|
prerelease: false
|
25
|
-
version_requirements: *
|
26
|
+
version_requirements: *70245880712420
|
26
27
|
- !ruby/object:Gem::Dependency
|
27
28
|
name: excon
|
28
|
-
requirement: &
|
29
|
+
requirement: &70245880711820 !ruby/object:Gem::Requirement
|
29
30
|
none: false
|
30
31
|
requirements:
|
31
32
|
- - ! '>='
|
@@ -33,10 +34,10 @@ dependencies:
|
|
33
34
|
version: '0'
|
34
35
|
type: :runtime
|
35
36
|
prerelease: false
|
36
|
-
version_requirements: *
|
37
|
+
version_requirements: *70245880711820
|
37
38
|
- !ruby/object:Gem::Dependency
|
38
39
|
name: yajl-ruby
|
39
|
-
requirement: &
|
40
|
+
requirement: &70245880711180 !ruby/object:Gem::Requirement
|
40
41
|
none: false
|
41
42
|
requirements:
|
42
43
|
- - ! '>='
|
@@ -44,10 +45,10 @@ dependencies:
|
|
44
45
|
version: '0'
|
45
46
|
type: :runtime
|
46
47
|
prerelease: false
|
47
|
-
version_requirements: *
|
48
|
+
version_requirements: *70245880711180
|
48
49
|
- !ruby/object:Gem::Dependency
|
49
50
|
name: kpeg
|
50
|
-
requirement: &
|
51
|
+
requirement: &70245880710740 !ruby/object:Gem::Requirement
|
51
52
|
none: false
|
52
53
|
requirements:
|
53
54
|
- - ! '>='
|
@@ -55,29 +56,34 @@ dependencies:
|
|
55
56
|
version: '0'
|
56
57
|
type: :development
|
57
58
|
prerelease: false
|
58
|
-
version_requirements: *
|
59
|
+
version_requirements: *70245880710740
|
59
60
|
description:
|
60
61
|
email: brian@generalassemb.ly
|
61
62
|
executables: []
|
62
63
|
extensions: []
|
63
64
|
extra_rdoc_files: []
|
64
65
|
files:
|
66
|
+
- checks/all.rb
|
67
|
+
- checks/core/check_array.rb
|
68
|
+
- checks/core/check_document.rb
|
69
|
+
- checks/core/check_hash.rb
|
70
|
+
- checks/setup.rb
|
65
71
|
- hyperdoc.gemspec
|
72
|
+
- library/hyperdoc/agent.rb
|
66
73
|
- library/hyperdoc/array.rb
|
67
74
|
- library/hyperdoc/box.rb
|
75
|
+
- library/hyperdoc/couch/database.rb
|
76
|
+
- library/hyperdoc/couch/document.rb
|
77
|
+
- library/hyperdoc/couch/view.rb
|
68
78
|
- library/hyperdoc/couch.rb
|
79
|
+
- library/hyperdoc/document.rb
|
80
|
+
- library/hyperdoc/factory.rb
|
69
81
|
- library/hyperdoc/hash.rb
|
70
|
-
- library/hyperdoc/link.rb
|
71
82
|
- library/hyperdoc/meta.rb
|
72
|
-
- library/hyperdoc/
|
73
|
-
- library/hyperdoc/schema.rb
|
74
|
-
- library/hyperdoc/selector.rb
|
75
|
-
- library/hyperdoc/value.rb
|
83
|
+
- library/hyperdoc/type.rb
|
76
84
|
- library/hyperdoc.rb
|
77
85
|
- rakefile
|
78
86
|
- README.md
|
79
|
-
- test/check_all.rb
|
80
|
-
- test/setup.rb
|
81
87
|
homepage: https://github.com/generalassembly/hyperdoc
|
82
88
|
licenses: []
|
83
89
|
post_install_message:
|
data/library/hyperdoc/value.rb
DELETED
File without changes
|