motion_blender 0.1.7 → 0.2.0

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.
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