dotum 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.groc.json +6 -0
  4. data/.rspec +4 -0
  5. data/.simplecov +5 -0
  6. data/.travis.yml +15 -0
  7. data/CONTRIBUTING.md +63 -0
  8. data/Gemfile +59 -0
  9. data/Guardfile +30 -0
  10. data/MIT-LICENSE.md +21 -0
  11. data/README.md +24 -0
  12. data/Rakefile +15 -0
  13. data/bin/dotum +7 -0
  14. data/data/default_rules.dotum +44 -0
  15. data/dotum.gemspec +19 -0
  16. data/extern/json/CHANGES.md +9 -0
  17. data/extern/json/COPYING +58 -0
  18. data/extern/json/README.rdoc +358 -0
  19. data/extern/json/lib/json.rb +62 -0
  20. data/extern/json/lib/json/.DS_Store +0 -0
  21. data/extern/json/lib/json/add/bigdecimal.rb +28 -0
  22. data/extern/json/lib/json/add/complex.rb +22 -0
  23. data/extern/json/lib/json/add/core.rb +11 -0
  24. data/extern/json/lib/json/add/date.rb +34 -0
  25. data/extern/json/lib/json/add/date_time.rb +50 -0
  26. data/extern/json/lib/json/add/exception.rb +31 -0
  27. data/extern/json/lib/json/add/ostruct.rb +31 -0
  28. data/extern/json/lib/json/add/range.rb +29 -0
  29. data/extern/json/lib/json/add/rational.rb +22 -0
  30. data/extern/json/lib/json/add/regexp.rb +30 -0
  31. data/extern/json/lib/json/add/struct.rb +30 -0
  32. data/extern/json/lib/json/add/symbol.rb +25 -0
  33. data/extern/json/lib/json/add/time.rb +38 -0
  34. data/extern/json/lib/json/common.rb +487 -0
  35. data/extern/json/lib/json/generic_object.rb +70 -0
  36. data/extern/json/lib/json/pure.rb +21 -0
  37. data/extern/json/lib/json/pure/generator.rb +522 -0
  38. data/extern/json/lib/json/pure/parser.rb +359 -0
  39. data/extern/json/lib/json/version.rb +8 -0
  40. data/lib/dotum.rb +11 -0
  41. data/lib/dotum/abstract_rules.rb +5 -0
  42. data/lib/dotum/abstract_rules/base.rb +56 -0
  43. data/lib/dotum/abstract_rules/globbable_files.rb +51 -0
  44. data/lib/dotum/abstract_rules/options_base.rb +33 -0
  45. data/lib/dotum/autoload_convention.rb +34 -0
  46. data/lib/dotum/cli.rb +35 -0
  47. data/lib/dotum/context.rb +55 -0
  48. data/lib/dotum/externs/json.rb +9 -0
  49. data/lib/dotum/logger.rb +50 -0
  50. data/lib/dotum/options_context.rb +21 -0
  51. data/lib/dotum/rule_dsl.rb +73 -0
  52. data/lib/dotum/rule_options_dsl.rb +116 -0
  53. data/lib/dotum/rule_runner.rb +16 -0
  54. data/lib/dotum/rules.rb +5 -0
  55. data/lib/dotum/rules/cd.rb +23 -0
  56. data/lib/dotum/rules/download.rb +32 -0
  57. data/lib/dotum/rules/link.rb +22 -0
  58. data/lib/dotum/rules/repo.rb +65 -0
  59. data/lib/dotum/rules/require_extension.rb +42 -0
  60. data/lib/dotum/rules/run.rb +23 -0
  61. data/lib/dotum/rules/use.rb +33 -0
  62. data/lib/dotum/rules/use_repo.rb +58 -0
  63. data/lib/dotum/standard_options.rb +5 -0
  64. data/lib/dotum/standard_options/destination.rb +22 -0
  65. data/lib/dotum/util.rb +5 -0
  66. data/lib/dotum/util/ansi_colors.rb +26 -0
  67. data/lib/dotum/util/path.rb +120 -0
  68. data/lib/dotum/version.rb +5 -0
  69. data/spec/fixtures/autoload_convention/abc_one_two_three.rb +7 -0
  70. data/spec/fixtures/autoload_convention/allcaps.rb +7 -0
  71. data/spec/fixtures/autoload_convention/mismatched.rb +3 -0
  72. data/spec/fixtures/autoload_convention/multi_token.rb +7 -0
  73. data/spec/fixtures/autoload_convention/single.rb +7 -0
  74. data/spec/fixtures/autoload_convention/string.rb +7 -0
  75. data/spec/spec_helper.rb +76 -0
  76. data/spec/unit/dotum/autoload_convention/const_missing_spec.rb +57 -0
  77. data/tasks/console.rake +9 -0
  78. data/tasks/spec.rake +7 -0
  79. data/tasks/spec/ci.rake +16 -0
  80. data/tasks/spec/coverage.rake +19 -0
  81. data/tasks/spec/mutate.rake +71 -0
  82. metadata +123 -0
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ class Dotum::AbstractRules::OptionsBase < Dotum::AbstractRules::Base
4
+
5
+ def self.exec(context, *args, &block)
6
+ options = option_defaults.merge(expand_shorthand(*args))
7
+ options.merge! eval_options_block(&block) if block
8
+
9
+ if errors = validate_options(options)
10
+ raise "Validation errors: #{errors.inspect}"
11
+ end
12
+
13
+ if respond_to? :expand_options
14
+ expand_options(context, options).map { |rule_options|
15
+ new(context, rule_options).exec
16
+ }
17
+ else
18
+ new(context, options).exec
19
+ end
20
+ end
21
+
22
+ def initialize(context, options)
23
+ super(context)
24
+
25
+ options.each do |option, value|
26
+ filter = self.class.option_configs[option][:filter]
27
+ value = instance_exec(value, &filter) if filter && !value.nil?
28
+
29
+ instance_variable_set(:"@#{option}", value)
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ # Autoload Convention
4
+ # ===================
5
+ # We adhere to a strict convention for the constants in this library:
6
+ #
7
+ # `Camel::Caps::BasedConstants` map to their underscore variants of
8
+ # `camel/caps/based_constants`.
9
+ #
10
+ # Each autoloadable parent module/class only needs to to `extend` the
11
+ # `AutoloadConvention` to bootstrap this behavior.
12
+ module Dotum
13
+ module AutoloadConvention
14
+
15
+ # `autoload` is dead, and we don't want to deal with its removal in 2.0,
16
+ # so here's a thread-unsafe poor man's solution.
17
+ def const_missing(sym)
18
+ full_sym = "#{name}::#{sym}"
19
+ path_parts = full_sym.split("::").map { |part|
20
+ part.gsub! /([^A-Z])([A-Z]+)/, "\\1_\\2" # OneTwo -> One_Two
21
+ part.gsub! /([A-Z]+)([A-Z][^A-Z]+)/, "\\1_\\2" # ABCOne -> ABC_One
22
+
23
+ part.downcase
24
+ }
25
+
26
+ require File.join(path_parts)
27
+
28
+ # Make sure that we don't get stuck in an endless loop. `const_get` calls
29
+ # into `const_missing`, so we can't use that.
30
+ eval "defined?(#{full_sym}) ? #{full_sym} : super"
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ class Dotum::CLI
4
+
5
+ def self.exec(args)
6
+ new(args).exec!
7
+ end
8
+
9
+ def initialize(args)
10
+ @args = args
11
+
12
+ @state_dir = Dotum::Util::Path.new("~/.dotum")
13
+ @target_dir = Dotum::Util::Path.new("~")
14
+ @package_dir = Dotum::Util::Path.new("~/.dotum/local")
15
+ end
16
+
17
+ def exec!
18
+ context = Dotum::Context.new(
19
+ # :no_remote => true,
20
+ :state_dir => @state_dir,
21
+ :target_dir => @target_dir,
22
+ :logger => Dotum::Logger.new
23
+ )
24
+
25
+ unless @package_dir.directory?
26
+ puts
27
+ puts "#{@package_dir.pretty} doesn't exist! Creating for now..."
28
+ @package_dir.mkpath!
29
+ end
30
+
31
+ Dotum::Rules::UseRepo.exec(context, @package_dir)
32
+ print "\n\n"
33
+ end
34
+
35
+ end
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ class Dotum::Context
4
+
5
+ def initialize(attributes={})
6
+ set_attributes(attributes)
7
+ end
8
+
9
+ attr_reader :package_dir
10
+ attr_reader :target_dir
11
+ attr_reader :state_dir
12
+
13
+ attr_reader :logger
14
+ attr_reader :depth
15
+
16
+ def no_remote?
17
+ @no_remote
18
+ end
19
+
20
+ def attributes
21
+ result = {}
22
+ instance_variables.each do |var_name|
23
+ result[var_name[1..-1].to_sym] = instance_variable_get(var_name)
24
+ end
25
+
26
+ result
27
+ end
28
+
29
+ def fork(new_attributes={})
30
+ self.class.new(attributes.merge(new_attributes || {}))
31
+ end
32
+
33
+ def child(new_attributes={})
34
+ new_attributes ||= {}
35
+ new_attributes[:depth] = (@depth || 0) + 1
36
+
37
+ fork(new_attributes)
38
+ end
39
+
40
+ private
41
+
42
+ def set_attributes(attributes)
43
+ attributes.each_pair do |key, value|
44
+ case key
45
+ when :package_dir then @package_dir = Dotum::Util::Path.new(value)
46
+ when :target_dir then @target_dir = Dotum::Util::Path.new(value)
47
+ when :state_dir then @state_dir = Dotum::Util::Path.new(value)
48
+ when :logger then @logger = value
49
+ when :no_remote then @no_remote = value
50
+ when :depth then @depth = value
51
+ end
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ begin
4
+ require "json"
5
+ rescue LoadError
6
+ # Fall back to the embedded pure-Ruby JSON implementation.
7
+ $LOAD_PATH.unshift(Dotum::EXTERN_PATH.join("json", "lib").to_s)
8
+ require "json"
9
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ class Dotum::Logger
4
+ include Dotum::Util::ANSIColors
5
+
6
+ INDENT = " "
7
+
8
+ def start_rule(rule)
9
+ @last_rule = rule
10
+ @last_rule_start = Time.now
11
+
12
+ print "\n"
13
+ print rule_line(rule)
14
+ end
15
+
16
+ def finish_rule(rule, status, reason)
17
+ message = "#{rule_line(rule)} - #{status.inspect} - #{reason.inspect}"
18
+ if @last_rule == rule
19
+ delta = (Time.now - @last_rule_start) * 1000.0
20
+ message += " (%.2fms)" % delta
21
+
22
+ print "\r"
23
+ else
24
+ print "\n\n"
25
+ end
26
+
27
+ print message
28
+ end
29
+
30
+ private
31
+
32
+ def rule_line(rule)
33
+ indent = INDENT * rule.context.depth
34
+ action = rule.class.pretty
35
+ subject = rule.pretty_subject
36
+
37
+ action = c_cyan(action)
38
+ subject = colorize_subject(subject)
39
+
40
+ "#{indent}#{action}: #{subject}"
41
+ end
42
+
43
+ SUBJECT_MATCHER = /^(.*?)( \(.+\))?$/
44
+ def colorize_subject(subject)
45
+ match = SUBJECT_MATCHER.match(subject)
46
+
47
+ "#{c_magenta(match[1])}#{match[2]}"
48
+ end
49
+
50
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require "set"
4
+
5
+ class Dotum::OptionsContext < Hash
6
+
7
+ def initialize(option_configs)
8
+ @known_options = Set.new(option_configs.keys)
9
+ end
10
+
11
+ def method_missing(sym, *args)
12
+ super if args.size != 1
13
+
14
+ unless @known_options.include? sym
15
+ raise ArgumentError, "Unknown option '#{sym}'"
16
+ end
17
+
18
+ self[sym] = args[0]
19
+ end
20
+
21
+ end
@@ -0,0 +1,73 @@
1
+ # encoding: utf-8
2
+
3
+ require "rbconfig"
4
+
5
+ module Dotum::RuleDSL
6
+
7
+ def success!(reason=nil)
8
+ throw :finish_rule, [:success, reason]
9
+ end
10
+
11
+ def failure!(reason=nil)
12
+ throw :finish_rule, [:failure, reason]
13
+ end
14
+
15
+ def skip!(reason=nil)
16
+ throw :finish_rule, [:skip, reason]
17
+ end
18
+
19
+ def platform?(name)
20
+ os = RbConfig::CONFIG["host_os"].downcase
21
+
22
+ case name
23
+ when /os\s?x/i then /mac|darwin/ === os
24
+ when /win(dows)?/i then /mswin|win|mingw/ === os
25
+ when /linux/i then /linux|cygwin/ === os
26
+ when /bsd/i then /bsd/ === os
27
+ when /solaris/i then /solaris|sunos/ === os
28
+ else
29
+ if name.is_a? Regexp
30
+ name === os
31
+ else
32
+ Regexp.new(name, "i") === os
33
+ end
34
+ end
35
+ end
36
+
37
+ def available?(command)
38
+ # TODO: Windows friendly.
39
+ `which "#{command}"`
40
+ $?.success?
41
+ end
42
+
43
+ def package_dir
44
+ context.package_dir
45
+ end
46
+
47
+ def target_dir
48
+ context.target_dir
49
+ end
50
+
51
+ def state_dir
52
+ context.state_dir
53
+ end
54
+
55
+ def method_missing(sym, *args, &block)
56
+ rule_class_name = sym.to_s.split("_").map(&:capitalize).join.to_sym
57
+
58
+ begin
59
+ rule_class = Dotum::Rules.const_get(rule_class_name)
60
+ rescue LoadError
61
+ raise NoMethodError, "Unknown rule #{sym}. Tried to load Dotum::Rules::#{rule_class_name}: #{$!.message}"
62
+ end
63
+
64
+ Dotum::RuleDSL.module_eval <<-end_eval, __FILE__, __LINE__
65
+ def #{sym}(*args, &block)
66
+ Dotum::Rules::#{rule_class_name}.exec(context, *args, &block)
67
+ end
68
+ end_eval
69
+
70
+ send(sym, *args, &block)
71
+ end
72
+
73
+ end
@@ -0,0 +1,116 @@
1
+ # encoding: utf-8
2
+
3
+ module Dotum::RuleOptionsDSL
4
+
5
+ OptionConfig = Struct.new(:filter, :validator, :default)
6
+
7
+
8
+ # DSL
9
+ # ---
10
+
11
+ def shorthand(*args)
12
+ @shorthand_config ||= args
13
+ end
14
+
15
+ def required(option, &block)
16
+ (@option_configs ||= {})[option] = OptionConfig.new(
17
+ block,
18
+ proc { |v| "Option '#{option}' is required." if v.nil? }
19
+ )
20
+ end
21
+
22
+ def optional(option, default=nil, &block)
23
+ (@option_configs ||= {})[option] = OptionConfig.new(block, nil, default)
24
+ end
25
+
26
+ def standard(option)
27
+ option_module_name = option.to_s.split("_").map(&:capitalize).join.to_sym
28
+
29
+ begin
30
+ option_module = Dotum::StandardOptions.const_get(option_module_name)
31
+ rescue LoadError
32
+ raise "Unknown standard option '#{option}'. Tried to load Dotum::StandardOptions::#{option_module_name}: #{$!.message}"
33
+ end
34
+
35
+ module_configs = option_module.instance_variable_get(:@option_configs)
36
+ unless module_configs && module_configs[option]
37
+ raise "Dotum::StandardOptions::#{option_module_name} is misconfigured; expected it to define the option '#{option}'"
38
+ end
39
+
40
+ include option_module
41
+ end
42
+
43
+ def register_preprocessor(sym)
44
+ @preprocessors ||= []
45
+ @preprocessors.push(sym)
46
+ end
47
+
48
+
49
+ # Configuration Management
50
+ # ------------------------
51
+
52
+ def option_configs
53
+ @memoized_option_configs ||= ancestors.reverse_each.reduce({}) { |result, ancestor|
54
+ result.merge(ancestor.instance_variable_get(:@option_configs) || {})
55
+ }
56
+ end
57
+
58
+ def option_defaults
59
+ @memoized_option_defaults ||= {}.tap do |defaults|
60
+ option_configs.each do |option, config|
61
+ defaults[option] = config[:default] unless config[:default].nil?
62
+ end
63
+ end
64
+ end
65
+
66
+ def preprocessor_methods
67
+ @memoized_preprocessor_methods ||= ancestors.map { |ancestor|
68
+ ancestor.instance_variable_get(:@preprocessors)
69
+ }.compact.flatten
70
+ end
71
+
72
+ def shorthand_config
73
+ return @shorthand_config if defined? @shorthand_config
74
+ return superclass.shorthand_config if superclass.respond_to? :shorthand_config
75
+
76
+ []
77
+ end
78
+
79
+ def expand_shorthand(*args)
80
+ result = {}
81
+ shorthand_config.zip(args).each do |config, value|
82
+ case config
83
+ when Symbol then result[config] = value
84
+ when Hash
85
+ if value.is_a? Hash
86
+ result[config.keys.first] = value.keys.first
87
+ result[config.values.first] = value.values.first
88
+ else
89
+ result[config.keys.first] = value
90
+ end
91
+ end
92
+ end
93
+
94
+ result
95
+ end
96
+
97
+ def eval_options_block(&block)
98
+ options = Dotum::OptionsContext.new(option_configs)
99
+ options.instance_eval(&block)
100
+
101
+ options
102
+ end
103
+
104
+ def validate_options(options)
105
+ errors = []
106
+ option_configs.each do |option, config|
107
+ next unless validator = config[:validator]
108
+ next unless error = validator.call(options[option])
109
+
110
+ errors.push(error)
111
+ end
112
+
113
+ errors.size > 0 ? errors : nil
114
+ end
115
+
116
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ class Dotum::RuleRunner
4
+ include Dotum::RuleDSL
5
+
6
+ def self.eval(context, *args, &block)
7
+ new(context).instance_eval(*args, &block)
8
+ end
9
+
10
+ def initialize(context)
11
+ @context = context
12
+ end
13
+
14
+ attr_reader :context
15
+
16
+ end