jsus 0.2.5 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -2
- data/VERSION +1 -1
- data/bin/jsus +15 -6
- data/jsus.gemspec +16 -15
- data/lib/jsus.rb +13 -13
- data/lib/jsus/container.rb +31 -28
- data/lib/jsus/package.rb +5 -6
- data/lib/jsus/packager.rb +6 -6
- data/lib/jsus/pool.rb +9 -12
- data/lib/jsus/source_file.rb +15 -15
- data/lib/jsus/tag.rb +5 -5
- data/lib/jsus/util.rb +7 -0
- data/lib/jsus/util/documenter.rb +118 -0
- data/lib/jsus/util/tree.rb +201 -0
- data/lib/jsus/util/validator.rb +8 -0
- data/lib/jsus/util/validator/base.rb +48 -0
- data/lib/jsus/util/validator/mooforge.rb +25 -0
- data/spec/jsus/pool_spec.rb +3 -3
- data/spec/jsus/{documenter_spec.rb → util/documenter_spec.rb} +3 -3
- data/spec/jsus/{tree_spec.rb → util/tree_spec.rb} +111 -27
- data/spec/jsus/{validator → util/validator}/base_spec.rb +5 -5
- data/spec/jsus/{validator → util/validator}/mooforge_spec.rb +7 -7
- metadata +18 -17
- data/lib/jsus/documenter.rb +0 -99
- data/lib/jsus/tree.rb +0 -124
- data/lib/jsus/validator.rb +0 -2
- data/lib/jsus/validator/base.rb +0 -38
- data/lib/jsus/validator/mooforge.rb +0 -19
data/lib/jsus/tag.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
#
|
2
|
-
# Tag is basically just a string that contains a package name and a name for class
|
3
|
-
# (or not necessarily a class) which the given SourceFile provides/requires/extends.
|
4
|
-
#
|
5
1
|
module Jsus
|
2
|
+
#
|
3
|
+
# Tag is basically just a string that contains a package name and a name for class
|
4
|
+
# (or not necessarily a class) which the given SourceFile provides/requires/extends/replaces.
|
5
|
+
#
|
6
6
|
class Tag
|
7
7
|
attr_accessor :package, :external # :nodoc:
|
8
8
|
|
@@ -57,7 +57,7 @@ module Jsus
|
|
57
57
|
#
|
58
58
|
# Returns a well-formed name for the tag.
|
59
59
|
# Options:
|
60
|
-
# * +:short:+
|
60
|
+
# * +:short:+ -- whether the tag should try using short form
|
61
61
|
#
|
62
62
|
# Important note: only non-external tags support short forms.
|
63
63
|
#
|
data/lib/jsus/util.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
module Jsus
|
2
|
+
module Util
|
3
|
+
# Very opinionated documenter class. It uses Murdoc to generate the
|
4
|
+
# documentation using the template and stylesheet bundled with the
|
5
|
+
# jsus gem file. Also generates indices for navigation.
|
6
|
+
class Documenter
|
7
|
+
# Default documenter options
|
8
|
+
DEFAULT_OPTIONS = {:highlight_source => true}
|
9
|
+
|
10
|
+
# Documenter options
|
11
|
+
attr_accessor :options
|
12
|
+
|
13
|
+
# Constructor. Accepts options as the argument.
|
14
|
+
def initialize(options = DEFAULT_OPTIONS)
|
15
|
+
require "murdoc"
|
16
|
+
self.options = options
|
17
|
+
rescue LoadError
|
18
|
+
raise "You should install murdoc gem in order to produce documentation"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Generates documentation tree into the given directory.
|
22
|
+
def generate(doc_dir = Dir.pwd)
|
23
|
+
#FileUtils.rm_rf(doc_dir)
|
24
|
+
FileUtils.mkdir_p(doc_dir)
|
25
|
+
template_path = File.dirname(__FILE__) + "/../../../markup"
|
26
|
+
template = File.read("#{template_path}/template.haml")
|
27
|
+
index_template = File.read("#{template_path}/index_template.haml")
|
28
|
+
stylesheet_path = "#{template_path}/stylesheet.css"
|
29
|
+
documented_sources.traverse(true) do |node|
|
30
|
+
if node.value # leaf
|
31
|
+
dir = doc_dir + File.dirname(node.full_path)
|
32
|
+
FileUtils.mkdir_p(dir)
|
33
|
+
file_from_contents(dir + "/#{node.name}.html", create_documentation_for_source(node.value, template))
|
34
|
+
else
|
35
|
+
dir = doc_dir + node.full_path
|
36
|
+
FileUtils.mkdir_p(dir)
|
37
|
+
FileUtils.cp(stylesheet_path, dir)
|
38
|
+
file_from_contents(dir + "/index.html", create_index_for_node(node, index_template))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Adds a source file to the documented source tree
|
44
|
+
def <<(source) # :nodoc:
|
45
|
+
filename = File.basename(source.filename)
|
46
|
+
if source.package
|
47
|
+
|
48
|
+
tree["#{source.package.name}/#{filename}"] = source
|
49
|
+
else
|
50
|
+
tree["#{filename}"] = source
|
51
|
+
end
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def tree # :nodoc:
|
56
|
+
@tree ||= Tree.new
|
57
|
+
end
|
58
|
+
|
59
|
+
# Scope for documentation in pathspec format. See Jsus::Util::Tree::Node#find_children_matching
|
60
|
+
def current_scope
|
61
|
+
@current_scope ||= default_scope
|
62
|
+
end
|
63
|
+
|
64
|
+
def default_scope # :nodoc:
|
65
|
+
["/**/*"]
|
66
|
+
end
|
67
|
+
|
68
|
+
def current_scope=(scope) # :nodoc:
|
69
|
+
@current_scope = scope
|
70
|
+
end
|
71
|
+
|
72
|
+
# Sets documenter to exclusive scope for documentation.
|
73
|
+
# Exclusive scope overrides all the other scopes.
|
74
|
+
def only(scope)
|
75
|
+
result = clone
|
76
|
+
result.current_scope = [scope].flatten
|
77
|
+
result
|
78
|
+
end
|
79
|
+
|
80
|
+
# Sets documenter to additive scope for documentation.
|
81
|
+
# Additive scopes match any of the pathspecs given
|
82
|
+
def or(scope)
|
83
|
+
result = clone
|
84
|
+
result.current_scope = current_scope + [scope].flatten
|
85
|
+
result
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns the tree with documented sources.
|
89
|
+
def documented_sources
|
90
|
+
@documented_sources ||= documented_sources!
|
91
|
+
end
|
92
|
+
|
93
|
+
def documented_sources! # :nodoc:
|
94
|
+
doctree = Tree.new
|
95
|
+
current_scope.map {|pathspec| tree.find_nodes_matching(pathspec) }.
|
96
|
+
flatten.each {|s| doctree.insert(s.full_path, s.value)}
|
97
|
+
doctree
|
98
|
+
end
|
99
|
+
|
100
|
+
protected
|
101
|
+
|
102
|
+
def create_documentation_for_source(source, template) # :nodoc:
|
103
|
+
skipped_lines = 0
|
104
|
+
content = source.original_content.gsub(/\A\s*\/\*.*?\*\//m) {|w| skipped_lines += w.split("\n").size; "" }
|
105
|
+
annotator = Murdoc::Annotator.new(content, :javascript, options)
|
106
|
+
Murdoc::Formatter.new(template).render(:paragraphs => annotator.paragraphs, :header => source.header, :source => source, :skipped_lines => skipped_lines)
|
107
|
+
end
|
108
|
+
|
109
|
+
def create_index_for_node(node, template) # :nodoc:
|
110
|
+
Haml::Engine.new(template).render(self, :node => node)
|
111
|
+
end
|
112
|
+
|
113
|
+
def file_from_contents(filename, contents) # :nodoc:
|
114
|
+
File.open(filename, "w+") {|f| f << contents }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
module Jsus
|
2
|
+
module Util
|
3
|
+
#
|
4
|
+
# Jsus::Tree is a basic hierarchical tree structure class
|
5
|
+
# What it does, basically, is maintaining hierarchical filesystem-like
|
6
|
+
# structure (with node names like /namespace/inner/item) and supporting
|
7
|
+
# lookups via #glob method.
|
8
|
+
#
|
9
|
+
# Example:
|
10
|
+
#
|
11
|
+
# tree = Jsus::Tree.new
|
12
|
+
# tree["/folder/item_0"] = "Hello"
|
13
|
+
# tree["/folder/item_1"] = "World"
|
14
|
+
# tree["/other/soul"] = "Empty"
|
15
|
+
# tree.glob("/*") # => 3 Jsus::Node-s (`root`, `folder`, `other`)
|
16
|
+
# tree.glob("/**/*") # => 6 Jsus::Node-s (`root`, `folder`, `other`, `item_0`, `item_1`, `soul`)
|
17
|
+
# tree["/something"] # => nil
|
18
|
+
# tree["/folder/item_1"] # => Jsus::Node
|
19
|
+
# tree["/other/soul"] = nil
|
20
|
+
# tree.leaves(true) # => 2 Jsus::Node-s (no `soul` node)
|
21
|
+
# tree.leaves(false) # => 3 Jsus::Node-s
|
22
|
+
#
|
23
|
+
class Tree
|
24
|
+
PATH_SEPARATOR = "/"
|
25
|
+
|
26
|
+
|
27
|
+
class <<self
|
28
|
+
# Utility functions
|
29
|
+
|
30
|
+
# Splits path into components
|
31
|
+
# Jsus::Tree.components_from_path("/hello/world") # => ["hello", "world"]
|
32
|
+
def components_from_path(path)
|
33
|
+
raise "Empty path given: #{path.inspect}" if !path || path == ""
|
34
|
+
path = path.to_s.dup
|
35
|
+
path.split(PATH_SEPARATOR).reject {|comp| comp == "" }
|
36
|
+
end
|
37
|
+
alias_method :get_path_components, :components_from_path
|
38
|
+
|
39
|
+
# Joins components into a pathspec
|
40
|
+
# Jsus::Tree.path_from_components(["hello", "world"]) # => "/hello/world"
|
41
|
+
def path_from_components(components)
|
42
|
+
"#{PATH_SEPARATOR}#{components.join(PATH_SEPARATOR)}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Jsus::Tree node class.
|
48
|
+
# Most of the time you only need to extract #value from the node,
|
49
|
+
# although sometimes you might need to refer to #parent node and #full_path
|
50
|
+
#
|
51
|
+
class Node
|
52
|
+
# Contains assigned value
|
53
|
+
attr_accessor :value
|
54
|
+
# Contains reference to parent node, nil for root node
|
55
|
+
attr_accessor :parent
|
56
|
+
# Contains array with path components
|
57
|
+
attr_accessor :path_components
|
58
|
+
|
59
|
+
# Initializes full path and value for the node
|
60
|
+
def initialize(full_path, value = nil)
|
61
|
+
self.full_path = full_path
|
62
|
+
self.value = value
|
63
|
+
end
|
64
|
+
|
65
|
+
# Contains full path to the node, such as '/hello/world'
|
66
|
+
attr_reader :full_path
|
67
|
+
# Contains node basename, such as 'world' for '/hello/world'
|
68
|
+
attr_reader :name
|
69
|
+
# Assigns node's full path and automatically deduces path components,
|
70
|
+
# basename etc.
|
71
|
+
def full_path=(full_path)
|
72
|
+
@full_path = full_path
|
73
|
+
@path_components = Tree.get_path_components(full_path)
|
74
|
+
@name = @path_components[-1]
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns node's direct descendants
|
78
|
+
def children
|
79
|
+
@children ||= []
|
80
|
+
end
|
81
|
+
|
82
|
+
# Finds a node child by basename
|
83
|
+
def find_child(name)
|
84
|
+
children.detect {|child| child.name == name }
|
85
|
+
end
|
86
|
+
|
87
|
+
# Creates a child with given name and value
|
88
|
+
def create_child(name, value = nil)
|
89
|
+
full_path = Tree.path_from_components(path_components + [name])
|
90
|
+
node = Node.new(full_path, value)
|
91
|
+
children << node
|
92
|
+
node.parent = self
|
93
|
+
node
|
94
|
+
end
|
95
|
+
|
96
|
+
# Finds a child with given name or creates a child with given name and
|
97
|
+
# value
|
98
|
+
def find_or_create_child(name, value = nil)
|
99
|
+
find_child(name) || create_child(name, value)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Finds children matching the given pathspec
|
103
|
+
# Pathspec format:
|
104
|
+
# '**' -- this node and all the children nodes that have children
|
105
|
+
# 'smth*' -- nodes beginning with smth
|
106
|
+
# 'smth*else' -- nodes beginning with smth and ending with else
|
107
|
+
# <string without asterisks> -- plain node lookup by name
|
108
|
+
# Returns array with search results
|
109
|
+
def find_children_matching(pathspec)
|
110
|
+
case pathspec
|
111
|
+
when "**"
|
112
|
+
[self] + children.select {|child| child.has_children? }
|
113
|
+
when /\*/
|
114
|
+
regexp = Regexp.new("^" + Regexp.escape(pathspec).gsub("\\*", ".*") + "$")
|
115
|
+
children.select {|child| !child.has_children? && child.name =~ regexp }
|
116
|
+
else
|
117
|
+
[find_child(pathspec)].compact
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns whether this node has children
|
122
|
+
def has_children?
|
123
|
+
!children.empty?
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Root node of the tree
|
128
|
+
def root
|
129
|
+
@root ||= Node.new("/", nil)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Looks up a node by direct path. Does not support wildcards
|
133
|
+
def lookup(path)
|
134
|
+
path_components = self.class.get_path_components(path)
|
135
|
+
path_components.inject(root) do |result, component|
|
136
|
+
if result
|
137
|
+
result.find_child(component)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def [](path)
|
143
|
+
node = lookup(path)
|
144
|
+
node ? node.value : nil
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
|
149
|
+
# Searches for nodes by a given pathspec
|
150
|
+
# See Jsus::Util::Tree::Node#find_children_matching for more details
|
151
|
+
def find_nodes_matching(pathspec)
|
152
|
+
self.class.get_path_components(pathspec).inject([root]) do |nodes, component|
|
153
|
+
nodes.map {|node| node.find_children_matching(component) }.flatten
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Returns values for nodes matching given pathspec
|
158
|
+
# See Jsus::Util::Tree::Node#find_children_matching for more details
|
159
|
+
def glob(pathspec)
|
160
|
+
find_nodes_matching(pathspec).map {|node| node.value }
|
161
|
+
end
|
162
|
+
|
163
|
+
# Inserts a node with given value into the tree
|
164
|
+
def insert(full_path, value = nil)
|
165
|
+
node = create_all_nodes_if_needed(full_path)
|
166
|
+
node.value = value
|
167
|
+
node
|
168
|
+
end
|
169
|
+
alias_method :[]=, :insert
|
170
|
+
|
171
|
+
# Traverses the tree.
|
172
|
+
# When given true as the argument, traverses all nodes.
|
173
|
+
# Otherwise, only leaves.
|
174
|
+
def traverse(all_nodes = false)
|
175
|
+
node_list = [root]
|
176
|
+
while !node_list.empty?
|
177
|
+
node = node_list.shift
|
178
|
+
yield node if all_nodes || !node.has_children?
|
179
|
+
node.children.each {|child| node_list << child }
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Returns a list of leaves.
|
184
|
+
# Returns only leaves with set values by default
|
185
|
+
def leaves(only_with_value = true)
|
186
|
+
result = []
|
187
|
+
traverse {|node| result << node if !only_with_value || node.value }
|
188
|
+
result
|
189
|
+
end
|
190
|
+
|
191
|
+
protected
|
192
|
+
|
193
|
+
def create_all_nodes_if_needed(full_path) # :nodoc:
|
194
|
+
self.class.get_path_components(full_path).inject(root) do |result, component|
|
195
|
+
result.find_or_create_child(component)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Jsus
|
2
|
+
module Util
|
3
|
+
# Base for any validator class.
|
4
|
+
module Validator
|
5
|
+
class Base
|
6
|
+
# Constructor accepts pool or array or container and adds every file
|
7
|
+
# to its source files set.
|
8
|
+
def initialize(pool_or_array_or_container)
|
9
|
+
self.source_files = pool_or_array_or_container
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns source files for validation
|
13
|
+
def source_files
|
14
|
+
@source_files ||= []
|
15
|
+
end
|
16
|
+
alias_method :sources, :source_files
|
17
|
+
|
18
|
+
# Sets source files for validation
|
19
|
+
def source_files=(pool_or_array_or_container)
|
20
|
+
case pool_or_array_or_container
|
21
|
+
when Pool
|
22
|
+
@source_files = pool_or_array_or_container.sources.to_a
|
23
|
+
when Array
|
24
|
+
@source_files = pool_or_array_or_container
|
25
|
+
when Container
|
26
|
+
@source_files = pool_or_array_or_container.to_a
|
27
|
+
end
|
28
|
+
end
|
29
|
+
alias_method :sources=, :source_files=
|
30
|
+
|
31
|
+
# Returns whether or not given sources conform to given set of rules
|
32
|
+
def validate
|
33
|
+
validation_errors.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
# List of validation errors, override this method on descendant classes.
|
37
|
+
def validation_errors
|
38
|
+
[]
|
39
|
+
end
|
40
|
+
|
41
|
+
# Shortcut for creating and validating a list of items
|
42
|
+
def self.validate(*args)
|
43
|
+
new(*args).validate
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end # Util
|
48
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Jsus
|
2
|
+
module Util
|
3
|
+
module Validator
|
4
|
+
# Mooforge validator checks every file for the following:
|
5
|
+
# * Presence of header
|
6
|
+
# * Presence of authors field
|
7
|
+
# * Presence of license field
|
8
|
+
class Mooforge < Base
|
9
|
+
def validation_errors # :nodoc:
|
10
|
+
@validation_errors ||= sources.inject([]) do |result, sf|
|
11
|
+
if !sf.header
|
12
|
+
result << "#{sf.filename} is missing header"
|
13
|
+
elsif !sf.header["authors"]
|
14
|
+
result << "#{sf.filename} is missing authors"
|
15
|
+
elsif !sf.header["license"]
|
16
|
+
result << "#{sf.filename} is missing license"
|
17
|
+
else
|
18
|
+
result
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end # Util
|
25
|
+
end
|
data/spec/jsus/pool_spec.rb
CHANGED
@@ -147,7 +147,7 @@ describe Jsus::Pool do
|
|
147
147
|
subject { Jsus::Pool.new(input_dir) }
|
148
148
|
|
149
149
|
it "should return a tree with all the source elements in it" do
|
150
|
-
subject.source_tree["/Core/Class.js"].
|
150
|
+
subject.source_tree["/Core/Class.js"].should be_a(Jsus::SourceFile)
|
151
151
|
end
|
152
152
|
|
153
153
|
it "should not choke when sources got no referenced package" do
|
@@ -161,11 +161,11 @@ describe Jsus::Pool do
|
|
161
161
|
subject { Jsus::Pool.new(input_dir) }
|
162
162
|
|
163
163
|
it "should return a tree with all the source elements in it" do
|
164
|
-
subject.provides_tree.glob("/Core/Class")[0].
|
164
|
+
subject.provides_tree.glob("/Core/Class")[0].should == Jsus::Tag["Core/Class"]
|
165
165
|
end
|
166
166
|
|
167
167
|
it "should allow wildcards" do
|
168
|
-
subject.provides_tree.glob("/Core/*")[0].
|
168
|
+
subject.provides_tree.glob("/Core/*")[0].should == Jsus::Tag["Core/Class"]
|
169
169
|
end
|
170
170
|
end
|
171
171
|
|