tool-shed 0.0.7 → 0.0.9

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 CHANGED
@@ -1,22 +1,16 @@
1
1
  # Tool Shed
2
2
 
3
3
  A collection of utility scripts to help working with ActionScript and Flex
4
- projects. These scripts are under development, so **don't** expect reliability.
4
+ projects. They are under development, so **don't** expect too much reliability.
5
5
 
6
- All tools have help available on the command line, to view use:
7
-
8
- as-tool-name -h
6
+ All tools have help available on the command line, to view use: `as-tool-name -h`
9
7
 
10
8
  ### as-docp
11
9
 
12
10
  The `as-docp` tool can be used to generate a `flex-config.xml` file from package
13
11
  level ASDoc files. This can then be used by the `asdoc` tool when generating
14
- ASDocs for your project.
15
-
16
- To document a package create a single file with a `.asdoc` suffix to contain
17
- your ASDoc comments.
18
-
19
- Example use:
12
+ ASDocs for your project. To document a package create a single file with a
13
+ `.asdoc` suffix to contain your ASDoc comments.
20
14
 
21
15
  as-docp -s src -o tmp/asdocp-config.xml
22
16
 
@@ -25,8 +19,6 @@ Example use:
25
19
  Scans a specified source tree for ActionScript and MXML files and for each one
26
20
  found creates a manifest entry. When complete writes the results to disk.
27
21
 
28
- Example use:
29
-
30
22
  as-manifest
31
23
  as-manifest -s source/main -o project-manifest.xml
32
24
  as-manifest -f 'org.helvector'
@@ -37,19 +29,16 @@ Compares a `mxmlc` generated `link-report.xml` against a `manifest.xml` file to
37
29
  identify files that are in a project source tree but are no longer compiled
38
30
  into the application.
39
31
 
40
- Example use:
41
-
42
32
  as-class-vacuum -s src/main -o report/vacuum/class.xml -l report/link/app-link-report.xml -m manifest.xml
43
33
 
44
- To generate a link report via mxmlc use `mxmlc -link-report=report.xml`
34
+ To generate a link report via mxmlc use `-link-report=report.xml` in the compiler
35
+ arguments.
45
36
 
46
37
  ### as-style-vacuum
47
38
 
48
39
  Loads all styles defined in **css** files (mxml isn't included) and identifies
49
40
  styles that are not referenced in the source tree.
50
41
 
51
- Example use:
52
-
53
42
  as-style-vacuum -c source/assets -s source/main -o report/vacuum/style.xml
54
43
 
55
44
  ### as-asset-vacuum
@@ -58,10 +47,20 @@ This script scans a source tree for assets of types `jpg, jpeg, png, otf, ttf,
58
47
  swf, svg, mp3, gif` then searches all ActionScript, CSS and MXML files to
59
48
  identify which assets are not referenced in the source files.
60
49
 
61
- Example use:
62
-
63
50
  as-asset-vacuum
64
51
  as-asset-vacuum -s source/main -o report/vacuum/asset.xml
52
+
53
+ ### as-concrete
54
+
55
+ Takes an Interface and generates a concrete class from it. Output is directed to
56
+ standard out. Using the `--type` argument will change the format, by default an
57
+ ActionScript class is generated, using `-t imp` only outputs the accessor and
58
+ method implementations, and `-t mock4as` will generate a Mock4AS class.
59
+
60
+ as-concrete -i IShed.as
61
+ as-concrete -i IShed.as -t mock4as
62
+ as-concrete -i IShed.as -t class
63
+ as-concrete -i IShed.as -t imp
65
64
 
66
65
  ## Install
67
66
 
data/bin/as-concrete ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
4
+
5
+ require 'tool_shed'
6
+
7
+ begin
8
+
9
+ opt = ConcreteOpts.parse(ARGV)
10
+ Concrete.new(opt)
11
+
12
+ rescue OptionParser::ParseError => e
13
+
14
+ puts e
15
+
16
+ end
@@ -6,18 +6,17 @@
6
6
  # no longer used by the application.
7
7
  #
8
8
  class AssetVacuum < Tool
9
- attr_reader :assets, :declared, :unused
9
+ attr_reader :assets,
10
+ :declared,
11
+ :unused
10
12
 
11
13
  def initialize(opt,out=STDOUT)
12
14
  super(opt,out)
13
15
 
14
16
  @src = opt[:src]
15
- @assets, @src_files, @declared = [], [], []
17
+ @assets, @src_files, @declared, @unused = [], [], [], []
16
18
 
17
- unless valid_opts
18
- @out.puts "#{INVALID_OPTS} The source directory does not exist."
19
- return
20
- end
19
+ do_exit unless valid_opts
21
20
 
22
21
  detect
23
22
 
@@ -27,25 +26,21 @@ class AssetVacuum < Tool
27
26
  end
28
27
 
29
28
  #
30
- # Valid if the specified project directory exists.
29
+ # Validates the given opts. Returns a boolean indicating if the src directory
30
+ # specified can be used.
31
31
  #
32
32
  def valid_opts
33
33
  File.exist?(@src) rescue false
34
34
  end
35
35
 
36
+ #
37
+ # Scans the project and detects usage statitics for the assets it's finds.
38
+ #
36
39
  def detect
37
40
  puts "Scanning project for assets that are unused..."
38
41
 
39
- Search.find_all(/\.(jpg|jpeg|png|otf|ttf|swf|svg|mp3|gif)$/,@src,@excludes) do |path|
40
- @assets << path
41
- end
42
-
43
- src_dec = scan_dirs(/\.(as|mxml|css)$/, @src, /Embed\(source=['"]([\w._\-\/]+)['"]/)
44
- css_dec = scan_dirs(/\.(css)$/, @src, /:\s*url\(\s*['"](.*)['"]/)
45
- mxml_dec = scan_dirs(/\.(mxml)$/, @src, /@Embed\(['"]([\w._\-\/]+)['"]/)
46
-
47
- @declared = src_dec + css_dec + mxml_dec
48
- @unused = []
42
+ scan_for_assets
43
+ scan_for_declared
49
44
 
50
45
  @assets.each { |ass| @unused << ass unless is_asset_used(ass) }
51
46
 
@@ -55,11 +50,29 @@ class AssetVacuum < Tool
55
50
  private
56
51
 
57
52
  #
58
- # Summarise the collected data.
53
+ # Finds all assets in the source directory.
54
+ #
55
+ def scan_for_assets
56
+ Search.find_all(/\.(jpg|jpeg|png|otf|ttf|swf|svg|mp3|gif)$/,@src,@excludes) do |path|
57
+ @assets << path
58
+ end
59
+ end
60
+
61
+ #
62
+ # Finds all asset declarations in the source files.
63
+ #
64
+ def scan_for_declared
65
+ @declared = scan_dirs(/\.(as|mxml|css)$/, @src, /Embed\(source=['"]([\w._\-\/]+)['"]/)
66
+ @declared += scan_dirs(/\.(css)$/, @src, /:\s*url\(\s*['"](.*)['"]/)
67
+ @declared += scan_dirs(/\.(mxml)$/, @src, /@Embed\(['"]([\w._\-\/]+)['"]/)
68
+ end
69
+
70
+ #
71
+ # Summarise the collected data and outputs a string detailing how many assets
72
+ # are used/unused in the project.
59
73
  #
60
74
  def summarise
61
- puts "Used assets: #{@declared.length.to_s}"
62
- puts "Unused assets: #{@unused.length.to_s}"
75
+ puts sprintf("Used assets: %d\nUnused assets: %d", @declared.length, @unused.length)
63
76
  end
64
77
 
65
78
  #
@@ -72,6 +85,10 @@ class AssetVacuum < Tool
72
85
  desc
73
86
  end
74
87
 
88
+ #
89
+ # Returns a boolean to indicate if the asset is referenced within the
90
+ # application.
91
+ #
75
92
  def is_asset_used(file)
76
93
  used = false
77
94
  @declared.each { |declaration|
@@ -82,4 +99,10 @@ class AssetVacuum < Tool
82
99
  used
83
100
  end
84
101
 
102
+ #
103
+ # Log an error message to disk and raise exit.
104
+ #
105
+ def do_exit
106
+ super "The source directory does not exist."
107
+ end
85
108
  end
@@ -20,11 +20,9 @@ class ClassVacuum < Tool
20
20
  @manifest = opt[:manifest]
21
21
  @link_regex = /<script name=".*\/(\w+)\.(as|mxml)/
22
22
  @manifest_regex = /<component id="(\w+)"/
23
+ @empty_packages = []
23
24
 
24
- unless valid_opts
25
- @out.puts "#{INVALID_OPTS} The link report, manifest file, or source directory does not exist."
26
- return
27
- end
25
+ do_exit unless valid_opts
28
26
 
29
27
  detect
30
28
 
@@ -33,10 +31,17 @@ class ClassVacuum < Tool
33
31
  to_disk(@report)
34
32
  end
35
33
 
34
+ #
35
+ # Valid if a link report, manifest and source directory has been supplied.
36
+ #
36
37
  def valid_opts
37
38
  File.exist?(@link_report) && File.exist?(@manifest) && File.exist?(@src) rescue false
38
39
  end
39
40
 
41
+ #
42
+ # Scans the project and detects classes that are in the source tree that are
43
+ # not in the compiler manifest report.
44
+ #
40
45
  def detect
41
46
  puts "Scanning project for classes that are uncompiled..."
42
47
 
@@ -44,7 +49,7 @@ class ClassVacuum < Tool
44
49
  @link_classes = linked(@link_report, @link_regex, 'link-report')
45
50
 
46
51
  @unused_classes = @manifest_classes-@link_classes
47
- @empty_packages = empties(@src)
52
+ find_empties(@src)
48
53
 
49
54
  summarise
50
55
  end
@@ -62,10 +67,8 @@ class ClassVacuum < Tool
62
67
  #
63
68
  # Scans the path for empty directories and lists them.
64
69
  #
65
- def empties(path)
66
- empties = []
67
- Search.for_empties(path) { |path| empties << path.sub( /^.*src\//, "") }
68
- empties
70
+ def find_empties(path)
71
+ Search.for_empties(path) { |path| @empty_packages << path.sub( /^.*src\//, "") }
69
72
  end
70
73
 
71
74
  #
@@ -98,4 +101,10 @@ class ClassVacuum < Tool
98
101
  classes
99
102
  end
100
103
 
104
+ #
105
+ # Log an error message to disk and raise exit.
106
+ #
107
+ def do_exit
108
+ super "The link report, manifest file, or source directory does not exist."
109
+ end
101
110
  end
@@ -0,0 +1,100 @@
1
+ # encoding: utf-8
2
+
3
+ #
4
+ # Takes an ActionScript 3 Interface file and generates a concrete implementation
5
+ # from it.
6
+ #
7
+ class Concrete < Tool
8
+ def initialize(opt,out=STDOUT)
9
+ super(opt,out)
10
+
11
+ @interface = opt[:interface]
12
+
13
+ do_exit unless valid_opts
14
+
15
+ create_mixer(opt[:type])
16
+ generate(File.new(@interface).read)
17
+ end
18
+
19
+ #
20
+ # Valid if an Interface has been supplied in the options.
21
+ #
22
+ def valid_opts
23
+ File.exist?(@interface) rescue false
24
+ end
25
+
26
+ #
27
+ # Parse the Interface and outputs the concrete document.
28
+ #
29
+ def generate(file)
30
+ @parser = Interface.new(file) rescue do_exit
31
+ output
32
+ end
33
+
34
+ private
35
+
36
+ #
37
+ # Output the constructed document.
38
+ #
39
+ def output
40
+ puts head + accessors + methods + foot
41
+ end
42
+
43
+ #
44
+ # Create the mixing tool which determines the output format.
45
+ #
46
+ def create_mixer(type)
47
+ mixers = { 'imp' => JustImplement,
48
+ 'class' => ActionScriptClass,
49
+ 'mock4as' => Mock4AS }
50
+
51
+ @mixer = mixers[type].new
52
+ @mixer
53
+ end
54
+
55
+ #
56
+ # Generate the file header.
57
+ #
58
+ def head
59
+ @mixer.head(@parser.class_name,@parser.name)
60
+ end
61
+
62
+ #
63
+ # Generate the accessor block.
64
+ #
65
+ def accessors
66
+ decs = ""
67
+ @parser.properties.each_pair { |name,property|
68
+ type = property[:type]
69
+
70
+ decs << @mixer.get(name,type) if property[:gets]
71
+ decs << @mixer.set(name,type) if property[:sets]
72
+ }
73
+ decs
74
+ end
75
+
76
+ #
77
+ # Generate the method block.
78
+ #
79
+ def methods
80
+ decs = ""
81
+ @parser.methods.each_pair { |name,method|
82
+ decs << @mixer.method(name, method[:arguments], method[:return])
83
+ }
84
+ decs
85
+ end
86
+
87
+ #
88
+ # Generate the file footer.
89
+ #
90
+ def foot
91
+ @mixer.foot
92
+ end
93
+
94
+ #
95
+ # Log an error message and raise exit.
96
+ #
97
+ def do_exit
98
+ super "The specified interface file does not exist, or is not an Interface."
99
+ end
100
+ end
@@ -0,0 +1,163 @@
1
+ # encoding: utf-8
2
+
3
+ #
4
+ # ActionScript 3 Interface Parser. Tokenises the contents of an interface into
5
+ # hashes.
6
+ #
7
+ # All methods and properties are stored in Hashes. Details of methods can be
8
+ # obtained via :name String, :arguments Array, return: String. Properies have
9
+ # the keys :name String, :gets Boolean, :sets Boolean, and :type String.
10
+ #
11
+ class Interface
12
+ attr_reader :name,
13
+ :class_name,
14
+ :properties,
15
+ :methods,
16
+ :package
17
+
18
+ def initialize(string)
19
+ @doc = Stripper.ecma_comments(string)
20
+
21
+ @properties, @methods = {}, {}
22
+ @package, @name = '', ''
23
+
24
+ raise "Document is not an interface" unless is_valid
25
+ parse
26
+ end
27
+
28
+ #
29
+ # Returns the method hash associated with request name.
30
+ #
31
+ def get_method(name)
32
+ @methods[name]
33
+ end
34
+
35
+ #
36
+ # Returns the proptert hash associated with request name.
37
+ #
38
+ def get_property(name)
39
+ @properties[name]
40
+ end
41
+
42
+ private
43
+
44
+ #
45
+ # Detect if the supplied string is a valid ActionScript Interface file.
46
+ #
47
+ def is_valid
48
+ @doc.scan(/^\s*public\s+(interface)\s+(\w+)\b/)
49
+ return true if $1 == "interface"
50
+ return false
51
+ end
52
+
53
+ #
54
+ # Parses the supplied string for all relevant information.
55
+ #
56
+ def parse
57
+ find_name
58
+ find_package
59
+ find_methods
60
+ find_getters
61
+ find_setters
62
+ end
63
+
64
+ #
65
+ # Finds the name of the interface.
66
+ #
67
+ def find_name
68
+ regexp = /^(\s+)?public\s+interface\s+(\w+)\b/
69
+ @doc.scan(regexp).each { |line|
70
+ @name = line[1]
71
+ @class_name = @name.sub(/^I/,'')
72
+ }
73
+ end
74
+
75
+ #
76
+ # Finds the package of the interface.
77
+ #
78
+ def find_package
79
+ regexp = /^(\s+)?package\s+([A-Za-z0-9.]+)/
80
+ @doc.scan(regexp).each { |line| @package = line[1] }
81
+ end
82
+
83
+ #
84
+ # Finds all methods defined in the interface.
85
+ #
86
+ def find_methods
87
+ regexp = /^\s*function\s+\b([a-z]\w+)\b\s*\((([^)\n]*)|(?m:[^)]+))\)\s*:\s*((\w+|\*))/
88
+
89
+ @doc.scan(regexp).each do |line|
90
+ add_method(line[0],line[1],line[3])
91
+ end
92
+ end
93
+
94
+ #
95
+ # Finds all getters defined in the interface.
96
+ #
97
+ def find_getters
98
+ regexp = accessor_regexp('get')
99
+
100
+ @doc.scan(regexp).each do |line|
101
+ prop = create_prop(line[1])
102
+ prop[:type] = line[5]
103
+ prop[:gets] = true;
104
+ end
105
+ end
106
+
107
+ #
108
+ # Finds all setters defined in the interface.
109
+ #
110
+ def find_setters
111
+ regexp = accessor_regexp('set')
112
+
113
+ @doc.scan(regexp).each do |line|
114
+ prop = create_prop(line[1])
115
+ prop[:type] = line[2].split(':')[1]
116
+ prop[:sets] = true;
117
+ end
118
+ end
119
+
120
+ #
121
+ # Adds a method hash to the list of methods.
122
+ #
123
+ def add_method(name,arguments,returns)
124
+ @methods[name] = {
125
+ :name => name,
126
+ :arguments => parameterize(arguments),
127
+ :return => returns
128
+ }
129
+ end
130
+
131
+ #
132
+ # Converts method arguments into an arry of parameters.
133
+ #
134
+ def parameterize(params)
135
+ arr = []
136
+ params.gsub!(/(\s|\n)/,'')
137
+ params.scan(/(\b\w+\b\s*:\s*\b\w+\b(=\s*(['"].*['"]|\w+))?|(\.\.\.\w+))/).each do |match|
138
+ arr << match[0]
139
+ end
140
+ arr
141
+ end
142
+
143
+ #
144
+ # Constructs the regular expression used when finding accessors.
145
+ #
146
+ def accessor_regexp(type='get|set')
147
+ /^\s*function\s+\b(#{type})\b\s+\b(\w+)\b\s*\(([^)\n]*)(\)(\s*:\s*(\w+|\*))?)?/
148
+ end
149
+
150
+ #
151
+ # Creates a default property hash.
152
+ #
153
+ def create_prop(name)
154
+ unless @properties.has_key? name
155
+ @properties[name] = {
156
+ :gets => false,
157
+ :sets => false,
158
+ :name => name
159
+ }
160
+ end
161
+ @properties[name]
162
+ end
163
+ end
data/lib/shed/manifest.rb CHANGED
@@ -57,8 +57,8 @@ class Manifest < Tool
57
57
  #
58
58
  def process(list)
59
59
  list.uniq!
60
- list.sort! {|a,b| a[:xml] <=> b[:xml] }
61
- list.select { |e| e[:xml].include?(@filter) }
60
+ list.sort! { |before,after| before[:xml] <=> after[:xml] }
61
+ list.select { |element| element[:xml].include?(@filter) }
62
62
  end
63
63
 
64
64
  #
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+
3
+ #
4
+ # Takes an ActionScript 3 Interface file and generates a ActionScript class from
5
+ # it.
6
+ #
7
+ class ActionScriptClass
8
+
9
+ #
10
+ # Returns a string formatted as the head of a ActionScript document.
11
+ #
12
+ def head(name,interface)
13
+ "package\n{\n\nclass #{name} implements #{interface}\n{\n\n"
14
+ end
15
+
16
+ #
17
+ # Returns a string formatted as a public ActionScript getter.
18
+ #
19
+ def get(name,type)
20
+ template(name, '', type,'get ')
21
+ end
22
+
23
+ #
24
+ # Returns a string formatted as a public ActionScript setter.
25
+ #
26
+ def set(name,type)
27
+ template(name, "value:#{type}", 'void','set ')
28
+ end
29
+
30
+ #
31
+ # Returns a string formatted as a public ActionScript method.
32
+ #
33
+ def method(name,arguments,returns)
34
+ template(name,arguments,returns)
35
+ end
36
+
37
+ #
38
+ # Returns a string formatted as the footer of a ActionScript document.
39
+ #
40
+ def foot
41
+ "\n}\n}\n"
42
+ end
43
+
44
+ protected
45
+
46
+ #
47
+ # Utility to convert the specified arguments to valid ActionScript method
48
+ # parameters.
49
+ #
50
+ def parameterize(arguments)
51
+ arguments = arguments.join(', ') if arguments.is_a? Array
52
+ arguments
53
+ end
54
+
55
+ #
56
+ # Returns a string formatted as a public ActionScript method. If a type is
57
+ # specified the method will be an implicit getter or setter.
58
+ #
59
+ def template(name,arguments,returns,type='')
60
+ str = " public function #{type}#{name}(#{parameterize(arguments)}):#{returns}\n"
61
+ str << " {\n"
62
+ str << " return;\n" unless returns == 'void'
63
+ str << " }\n\n"
64
+ end
65
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ #
4
+ # Takes an ActionScript 3 Interface file and generates all method and accessor
5
+ # implementations from it.
6
+ #
7
+ class JustImplement < ActionScriptClass
8
+ def head(name,interface)
9
+ ""
10
+ end
11
+
12
+ def foot
13
+ ""
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ #
4
+ # Takes an ActionScript 3 Interface file and generates a Mock4AS class from it.
5
+ #
6
+ class Mock4AS < ActionScriptClass
7
+ def head(name,interface)
8
+ "package\n{\n\nclass #{name}Mock extends Mock implements #{interface}\n{\n\nimport org.mock4as.Mock;\n\n"
9
+ end
10
+
11
+ protected
12
+
13
+ def template(name,arguments,returns,type='')
14
+ params = parameterize(arguments)
15
+ record = (params == '') ? '' : ', ' + params.gsub(/:\w+\b/,"")
16
+
17
+ str = " public function #{type}#{name}(#{params}):#{returns}\n"
18
+ str << " {\n"
19
+ str << " record('#{name}'#{record});\n"
20
+ str << " return expectedReturnFor('#{name}') as #{returns};\n" unless returns == 'void'
21
+ str << " }\n\n"
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ #
4
+ # Manages the command line interface for the ActionScript 3 Mock Framework Class
5
+ # generation tool.
6
+ #
7
+ class ConcreteOpts < ToolOpts
8
+
9
+ def self.name
10
+ "as-concrete"
11
+ end
12
+
13
+ def self.description
14
+ "ActionScript Concrete Class Generator"
15
+ end
16
+
17
+ def self.default_config
18
+ dc = superclass.default_config
19
+ dc[:type] = 'class'
20
+ dc
21
+ end
22
+
23
+ def self.add_optional(op,config)
24
+ op.on("-i", "--interface FILE", String, "File path to ActionScript interface file.") do |value|
25
+ config[:interface] = value
26
+ end
27
+
28
+ op.on("-t", "--type STRING", String, "Optional output type, defaults to 'class'. Accepts 'class', 'mock4as' and 'imp'.") do |value|
29
+ config[:type] = value
30
+ end
31
+ end
32
+
33
+ end
@@ -109,7 +109,9 @@ class ToolOpts
109
109
 
110
110
  add_tail(options,out)
111
111
 
112
- options.parse!(args)
112
+ args = options.parse!(args)
113
+
114
+ config[:default] = args.shift
113
115
 
114
116
  config
115
117
  end