jsus 0.2.5 → 0.2.6
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/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
|
|