motion_blender 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 79ace285044eed0c6934798cf46c9a66db611fb3
4
- data.tar.gz: b2175ea70d081ad8b0e84889ce2b29caee909e09
3
+ metadata.gz: 79e7438cc7769076e46b9ad288b4f54fa75c53d5
4
+ data.tar.gz: f3e27ca0d88e10e203e4144ba61dc89a5aeffc58
5
5
  SHA512:
6
- metadata.gz: af125da568d66fb81fb615b94b562ce9aef8142e1f052a063247f1f057237e4ec086e1351629ec1986317e22d08d9ab3231e5bd4889c0a15ae984a7e722c8204
7
- data.tar.gz: eb3e1d7da01a76ae13bcb9421ca9d6ff36113dbca25a2516cda1bd25420de5572145412f76167942fdd9c60ac2322f6017dc0bb832854a295ae48e10530ec2f9
6
+ metadata.gz: 3578fd948e8db4018cf866376c90aa1ad0bbf23533d85591f75711e4862e8492d741dd42265c9c00dc8982bf0f31db7ca37b2ba0e40a520de528a88cfa9c6aaf
7
+ data.tar.gz: 0099a52ca69ddfbd9b3c24aadf2bb4760eb02cfd2b4f07550e212bad14f2bbbacb838812dfb05e5480bc07fd09f8a7e74c70fa48245d8756615965c5e7a4d6e9
data/.rubocop.yml CHANGED
@@ -61,6 +61,11 @@ Style/Lambda:
61
61
  Style/MethodDefParentheses:
62
62
  EnforcedStyle: require_no_parentheses
63
63
 
64
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
65
+ Style/MethodName:
66
+ Exclude:
67
+ - 'motion/motion_blender/**/*.rb'
68
+
64
69
  # Cop supports --auto-correct.
65
70
  Style/MultilineBlockLayout:
66
71
  Exclude:
data/README.md CHANGED
@@ -82,11 +82,11 @@ To require this *motion_hoge* makes an application or a gem to load functionalit
82
82
  `motion_blender` itself is excepted for analyzing,
83
83
  so don't worry to require `motion_blender` in *incept*-ed files.
84
84
 
85
- ### Limitation
85
+ ### Parsing
86
86
 
87
- Currently, `require` has some limitation because of the way how to analyze the code.
87
+ It parses `require` statements properly in almost all the common cases.
88
88
 
89
- The argument must be a string or an eval-able expression:
89
+ Argument can be a string or an eval-able expression:
90
90
 
91
91
  ```ruby
92
92
  # Good
@@ -103,10 +103,10 @@ Dir.glob('lib/**/*.rb').each { |path| require path }
103
103
  Dir[File.dirname(__FILE__) + '/lib/*.rb'].each { |file| require file }
104
104
  ```
105
105
 
106
- Required files must exist:
106
+ Takes care of rescue clause:
107
107
 
108
108
  ```ruby
109
- # Bad
109
+ # Good
110
110
  begin
111
111
  require 'may_not_exist'
112
112
  rescue LoadError
@@ -118,9 +118,9 @@ end
118
118
 
119
119
  In the RubyMotion application's Rakefile, `motion_blender` is to be required, typically via `Bundler.require`.
120
120
  Then it hooks `build` tasks.
121
- You can hit `rake -P` and see `motion_blender:analyze` task is hooked.
121
+ You can hit `rake -P` and see `motion_blender:apply` task is hooked.
122
122
 
123
- At the analyze task, MotionBlender runs analyzer on all `Motion::Project::Config#files`.
123
+ In apply task, MotionBlender runs analyzer on all `Motion::Project::Config#files`.
124
124
  It uses [parser](https://github.com/whitequark/parser) and follows all `require` and `require_relative`.
125
125
  After that, add the newly encountered files to the head of `Motion::Project::Config#files` and put file dependencies to `Motion::Project::Config#dependencies`.
126
126
 
@@ -5,17 +5,15 @@ require 'motion_blender/analyzer/parser'
5
5
  module MotionBlender
6
6
  class Analyzer
7
7
  attr_reader :files, :dependencies
8
- attr_accessor :exclude_files
9
8
 
10
9
  def initialize
11
10
  @analyzed_files = Set.new
12
- @exclude_files = Set.new
13
11
  @files = []
14
12
  @dependencies = {}
15
13
  end
16
14
 
17
15
  def analyze file, backtrace = []
18
- return if @exclude_files.include? file
16
+ return if MotionBlender.config.excepted_files.include? file
19
17
  return if @analyzed_files.include? file
20
18
  @analyzed_files << file
21
19
 
@@ -33,7 +31,6 @@ module MotionBlender
33
31
 
34
32
  def parse file, backtrace
35
33
  parser = Parser.new file
36
- parser.exclude_files = @exclude_files
37
34
  begin
38
35
  parser.run_callbacks :parse do
39
36
  parser.parse
@@ -1,3 +1,6 @@
1
+ require 'motion_blender/analyzer/require'
2
+ require 'motion_blender/analyzer/original_finder'
3
+
1
4
  module MotionBlender
2
5
  class Analyzer
3
6
  class Evaluator
@@ -13,23 +16,53 @@ module MotionBlender
13
16
  def parse_args
14
17
  extractor = create_extractor
15
18
  extractor.instance_eval(@ast.loc.expression.source, @file)
16
- extractor.instance_eval { @args || [] }
17
- rescue
18
- if stack.any?
19
+ extractor.instance_eval { @_args || [] }
20
+ rescue ScriptError => err
21
+ recover_from_script_error err
22
+ rescue StandardError => err
23
+ recover_from_standard_error err
24
+ end
25
+
26
+ def recover_from_script_error err
27
+ i = @stack.find_index { |ast| ast.type == :rescue }
28
+ if i && i > 0
29
+ stack = @stack[0..(i - 1)]
19
30
  Evaluator.new(@file, stack.last, stack[0..-2], @method).parse_args
20
31
  else
21
- exp = @ast.loc.expression.source
22
- raise LoadError, "failed to parse `#{exp}'"
32
+ fail LoadError, err.message
33
+ end
34
+ end
35
+
36
+ def recover_from_standard_error err
37
+ if @stack.any?
38
+ Evaluator.new(@file, @stack.last, @stack[0..-2], @method).parse_args
39
+ else
40
+ fail LoadError, err.message
23
41
  end
24
42
  end
25
43
 
26
44
  def create_extractor
27
- obj = Object.new
28
- obj.define_singleton_method @method do |arg|
29
- @args ||= []
30
- @args << arg
45
+ file = @file
46
+ extractor = Evaluator.extractor_for(@method).new
47
+ extractor.instance_eval { @_file = file }
48
+ extractor
49
+ end
50
+
51
+ def self.extractor_for method
52
+ @extractor_classes ||= {}
53
+ @extractor_classes[method] ||= Class.new do
54
+ define_method method do |arg|
55
+ req = Require.new(@_file, method, arg)
56
+ unless req.excluded?
57
+ @_args ||= []
58
+ @_args << req
59
+ end
60
+ end
61
+
62
+ define_method :__ORIGINAL__ do
63
+ OriginalFinder.new(@_file).find
64
+ end
31
65
  end
32
- obj
33
66
  end
34
67
  end
35
68
  end
@@ -0,0 +1,26 @@
1
+ module MotionBlender
2
+ class Analyzer
3
+ class OriginalFinder
4
+ attr_reader :file, :original
5
+
6
+ def initialize file
7
+ @file = file
8
+ end
9
+
10
+ def find
11
+ dir = MotionBlender.config.motion_dirs.find { |d| @file.start_with? d }
12
+ fail 'not found in motion_dirs' unless dir
13
+ arg = Pathname.new(@file).relative_path_from(Pathname.new(dir))
14
+ @original = candidates_for(arg).find(&:file?).try(&:to_s)
15
+ end
16
+
17
+ def candidates_for arg
18
+ Enumerator.new do |y|
19
+ $LOAD_PATH.each do |dir|
20
+ y << Pathname.new(dir).join(arg)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -3,7 +3,6 @@ require 'active_support'
3
3
  require 'active_support/callbacks'
4
4
 
5
5
  require 'motion_blender/analyzer/evaluator'
6
- require 'motion_blender/analyzer/require'
7
6
 
8
7
  module MotionBlender
9
8
  class Analyzer
@@ -14,7 +13,6 @@ module MotionBlender
14
13
  REQUIREMENT_TOKENS = %i(motion_require require_relative require)
15
14
 
16
15
  attr_reader :file, :requires, :last_trace
17
- attr_accessor :exclude_files
18
16
 
19
17
  def initialize file
20
18
  @file = file.to_s
@@ -27,16 +25,8 @@ module MotionBlender
27
25
  end
28
26
 
29
27
  def traverse ast, stack = []
30
- @exclude_files ||= Set.new
31
28
  if require_command?(ast)
32
- @last_trace = trace_for ast
33
- Evaluator.new(@file, ast, stack).parse_args.each do |arg|
34
- req = Require.new(@file, ast.children[1], arg)
35
- next if @exclude_files.include? req.arg
36
- next if @exclude_files.include? req.file
37
- req.trace = @last_trace
38
- @requires << req
39
- end
29
+ evaluate ast, stack
40
30
  elsif !raketime_block?(ast)
41
31
  ast.children
42
32
  .select { |node| node.is_a?(::Parser::AST::Node) }
@@ -44,6 +34,14 @@ module MotionBlender
44
34
  end
45
35
  end
46
36
 
37
+ def evaluate ast, stack
38
+ @last_trace = trace_for ast
39
+ Evaluator.new(@file, ast, stack).parse_args.each do |req|
40
+ req.trace = @last_trace
41
+ @requires << req
42
+ end
43
+ end
44
+
47
45
  def require_command? ast
48
46
  (ast.type == :send) && REQUIREMENT_TOKENS.include?(ast.children[1])
49
47
  end
@@ -58,6 +58,11 @@ module MotionBlender
58
58
  def match? arg_or_file
59
59
  arg == arg_or_file || file == arg_or_file
60
60
  end
61
+
62
+ def excluded?
63
+ MotionBlender.config.builtin_features.include?(arg) ||
64
+ MotionBlender.config.excepted_files.include?(file)
65
+ end
61
66
  end
62
67
  end
63
68
  end
@@ -1,11 +1,15 @@
1
+ require 'set'
2
+
1
3
  module MotionBlender
2
4
  class Config
3
5
  attr_reader :incepted_files, :excepted_files, :motion_dirs
6
+ attr_reader :builtin_features
4
7
 
5
8
  def initialize
6
9
  @incepted_files = []
7
- @excepted_files = []
10
+ @excepted_files = Set.new
8
11
  @motion_dirs = []
12
+ @builtin_features = Set.new %w(bigdecimal rational date thread)
9
13
  end
10
14
  end
11
15
 
@@ -1,4 +1,5 @@
1
1
  require 'rake'
2
+ require 'yaml'
2
3
  require 'motion_blender/config'
3
4
  require 'motion_blender/analyzer'
4
5
 
@@ -10,16 +11,15 @@ module MotionBlender
10
11
 
11
12
  def analyze
12
13
  analyzer = Analyzer.new
13
- analyzer.exclude_files += builtin_features + config.excepted_files
14
-
15
14
  files = config.incepted_files + Motion::Project::App.config.files
16
15
  files.flatten.each do |file|
17
16
  analyzer.analyze file
18
17
  end
19
- apply analyzer
18
+ analyzer
20
19
  end
21
20
 
22
- def apply analyzer
21
+ def apply
22
+ analyzer = analyze
23
23
  Motion::Project::App.setup do |app|
24
24
  new_files = analyzer.files - app.files
25
25
  app.exclude_from_detect_dependencies += new_files
@@ -29,21 +29,27 @@ module MotionBlender
29
29
  end
30
30
  end
31
31
 
32
- def builtin_features
33
- %w(bigdecimal rational date thread)
32
+ def dump
33
+ analyzer = analyze
34
+ YAML.dump %w(files dependencies).map { |k| [k, analyzer.send(k)] }.to_h
34
35
  end
35
36
  end
36
37
  end
37
38
 
38
39
  namespace :motion_blender do
39
- task :analyze do
40
+ task :apply do
40
41
  MotionBlender.on_parse do |parser|
41
42
  Motion::Project::App.info('Analyze', parser.file)
42
43
  end
43
- MotionBlender::RakeTasks.new.analyze
44
+ MotionBlender::RakeTasks.new.apply
45
+ end
46
+
47
+ desc 'Dump analyzed files and dependencies'
48
+ task :dump do
49
+ puts MotionBlender::RakeTasks.new.dump
44
50
  end
45
51
  end
46
52
 
47
53
  %w(build:simulator build:device).each do |t|
48
- task t => 'motion_blender:analyze'
54
+ task t => 'motion_blender:apply'
49
55
  end
@@ -1,3 +1,3 @@
1
1
  module MotionBlender
2
- VERSION = '0.1.7'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -8,5 +8,8 @@ Module.new do
8
8
  def motion_require _
9
9
  end
10
10
 
11
+ def __ORIGINAL__
12
+ end
13
+
11
14
  Object.send :include, self
12
15
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion_blender
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - kayhide
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-10-20 00:00:00.000000000 Z
11
+ date: 2015-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -228,7 +228,7 @@ files:
228
228
  - lib/motion_blender.rb
229
229
  - lib/motion_blender/analyzer.rb
230
230
  - lib/motion_blender/analyzer/evaluator.rb
231
- - lib/motion_blender/analyzer/hooker.rb
231
+ - lib/motion_blender/analyzer/original_finder.rb
232
232
  - lib/motion_blender/analyzer/parser.rb
233
233
  - lib/motion_blender/analyzer/require.rb
234
234
  - lib/motion_blender/callbacks.rb
@@ -1,41 +0,0 @@
1
- module MotionBlender
2
- class Analyzer
3
- module Hooker
4
- module_function
5
-
6
- def active?
7
- !!@active
8
- end
9
-
10
- def activate
11
- @active = true
12
- end
13
-
14
- def deactivate
15
- @active = false
16
- end
17
-
18
- def requires
19
- @requires ||= Hash.new { |hash, key| hash[key] = [] }
20
- end
21
-
22
- def clear
23
- requires.clear
24
- end
25
- end
26
-
27
- module Hooks
28
- def require feature
29
- if Hooker.active?
30
- super
31
- src = caller.first.split(':', 2).first
32
- Hooker.requires[src] << feature
33
- else
34
- super
35
- end
36
- end
37
- end
38
- end
39
- end
40
-
41
- Object.send :include, MotionBlender::Analyzer::Hooks