tool-shed 0.0.7 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
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