hydramata-core 0.1.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 +7 -0
- data/.gitignore +15 -0
- data/.hound.yml +818 -0
- data/.rspec +2 -0
- data/.travis.yml +20 -0
- data/CONTRIBUTING.md +220 -0
- data/Gemfile +34 -0
- data/Guardfile +36 -0
- data/LICENSE +15 -0
- data/README.md +13 -0
- data/Rakefile +40 -0
- data/bin/rails +12 -0
- data/fs +3 -0
- data/gemfiles/rails4.1.gemfile +12 -0
- data/gemfiles/rails4.gemfile +13 -0
- data/hydramata-core.gemspec +35 -0
- data/lib/hydramata-core.rb +1 -0
- data/lib/hydramata/configuration.rb +17 -0
- data/lib/hydramata/core.rb +42 -0
- data/lib/hydramata/core/named_callbacks.rb +24 -0
- data/lib/hydramata/core/railtie.rb +14 -0
- data/lib/hydramata/core/runner.rb +58 -0
- data/lib/hydramata/core/translator.rb +72 -0
- data/lib/hydramata/core/version.rb +5 -0
- data/lib/hydramata/exceptions.rb +4 -0
- data/lib/hydramata/services.rb +21 -0
- data/lib/hydramata_core.rb +2 -0
- data/lib/tasks/hydramata_mecha_tasks.rake +4 -0
- data/run_each_spec_in_isolation +11 -0
- data/script/analyzer.rb +124 -0
- data/script/fast_specs +22 -0
- data/spec/README.md +10 -0
- data/spec/features/translation_services_spec.rb +35 -0
- data/spec/fixtures/core.translations.yml +8 -0
- data/spec/lib/hydramata-translations_spec.rb +7 -0
- data/spec/lib/hydramata/configuration_spec.rb +38 -0
- data/spec/lib/hydramata/core/named_callbacks_spec.rb +30 -0
- data/spec/lib/hydramata/core/runner_spec.rb +45 -0
- data/spec/lib/hydramata/core/translator_spec.rb +94 -0
- data/spec/lib/hydramata/services_spec.rb +27 -0
- data/spec/spec_fast_helper.rb +33 -0
- metadata +164 -0
@@ -0,0 +1 @@
|
|
1
|
+
require 'hydramata/core'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'active_support/lazy_load_hooks'
|
2
|
+
require 'hydramata/exceptions'
|
3
|
+
module Hydramata
|
4
|
+
class Configuration
|
5
|
+
def translator
|
6
|
+
@translator ||= begin
|
7
|
+
require 'hydramata/core/translator'
|
8
|
+
Core::Translator.new(base_scope: ['hydramata', 'core'])
|
9
|
+
end
|
10
|
+
end
|
11
|
+
def translator=(object)
|
12
|
+
raise ConfigurationError.new("Expected #{self.class}#translator to respond_to #translate. #{object.inspect} does not respond to #translate") unless object.respond_to?(:translate)
|
13
|
+
@translator = object
|
14
|
+
end
|
15
|
+
end
|
16
|
+
ActiveSupport.run_load_hooks(:hydramata_configuration, Configuration)
|
17
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'hydramata/core/railtie' if defined?(Rails)
|
2
|
+
|
3
|
+
module Hydramata
|
4
|
+
if defined?(ActiveSupport::Autoload)
|
5
|
+
extend ActiveSupport::Autoload
|
6
|
+
autoload :Services
|
7
|
+
autoload :Configuration
|
8
|
+
end
|
9
|
+
class << self
|
10
|
+
attr_writer :configuration
|
11
|
+
|
12
|
+
# @see Configuration
|
13
|
+
def configuration
|
14
|
+
require 'hydramata/configuration'
|
15
|
+
@configuration ||= Configuration.new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module_function
|
20
|
+
|
21
|
+
# @see Configuration
|
22
|
+
# @see .configuration
|
23
|
+
def configure(&block)
|
24
|
+
@configuration_block = block
|
25
|
+
|
26
|
+
# The Rails load sequence means that some of the configured Targets may
|
27
|
+
# not be loaded; As such I am not calling configure! instead relying on
|
28
|
+
# Hydra::RemoteIdentifier::Railtie to handle the configure! call
|
29
|
+
configure! unless defined?(Rails)
|
30
|
+
end
|
31
|
+
|
32
|
+
def configure!
|
33
|
+
if @configuration_block.respond_to?(:call)
|
34
|
+
@configuration_block.call(configuration)
|
35
|
+
@configuration_block = nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
private :configure!
|
39
|
+
|
40
|
+
module Core
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Hydramata
|
2
|
+
module Core
|
3
|
+
# Responsible for registering blocks used for callbacks.
|
4
|
+
class NamedCallbacks
|
5
|
+
def initialize
|
6
|
+
@callbacks = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing(callback_name, *args, &block)
|
10
|
+
@callbacks[callback_name] = block
|
11
|
+
end
|
12
|
+
|
13
|
+
def respond_to_missing?(callback_name)
|
14
|
+
@callbacks[callback_name]
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(callback_name, *args)
|
18
|
+
callback_name = callback_name.to_sym
|
19
|
+
callback = @callbacks[callback_name]
|
20
|
+
callback ? callback.call(*args) : true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails/railtie'
|
2
|
+
|
3
|
+
module Hydramata
|
4
|
+
module Core
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
config.eager_load_namespaces << Hydramata::Core
|
7
|
+
config.to_prepare do
|
8
|
+
# Because I want allow for other components to plug into Hydramata's
|
9
|
+
# configuration. Maybe there is a better way to do this.
|
10
|
+
Hydramata.send(:configure!)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Hydramata
|
2
|
+
module Core
|
3
|
+
# A Runner is responsible for performing the guts of what might traditionally
|
4
|
+
# be a controller's action.
|
5
|
+
#
|
6
|
+
# It exists for two reasons:
|
7
|
+
# * Controllers are extremely over-worked (parameter negotiation,
|
8
|
+
# authentication, authorization, marshalling an object, user messages via
|
9
|
+
# flash, and http response determination)
|
10
|
+
# * The inner method content of a controller's action is subject to change
|
11
|
+
# especially as other implementors look to change the behavior.
|
12
|
+
#
|
13
|
+
# So, the Runner provides a seem in the code in which you can more readily
|
14
|
+
# make changes to the "inner method" of a route. In some ways, I see this as
|
15
|
+
# a separation of state change and response; a somewhat analogous separation
|
16
|
+
# to the Command/Query separation principle.
|
17
|
+
#
|
18
|
+
# @See Services
|
19
|
+
class Runner
|
20
|
+
attr_reader :context
|
21
|
+
|
22
|
+
def self.run(context,*args,&block)
|
23
|
+
new(context, &block).run(*args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(context, collaborators = {})
|
27
|
+
@callbacks = collaborators.fetch(:callbacks) { default_callbacks }
|
28
|
+
self.context = context
|
29
|
+
yield(@callbacks) if block_given?
|
30
|
+
end
|
31
|
+
|
32
|
+
def callback(name, *args)
|
33
|
+
@callbacks.call(name, *args)
|
34
|
+
args
|
35
|
+
end
|
36
|
+
|
37
|
+
def services
|
38
|
+
context.services
|
39
|
+
end
|
40
|
+
|
41
|
+
def run(*args)
|
42
|
+
raise NotImplementedError.new("You must define #{self.class}#run")
|
43
|
+
end
|
44
|
+
protected
|
45
|
+
|
46
|
+
def context=(object)
|
47
|
+
raise RuntimeError.new("Expected #{object.inspect} to implement #services") unless object.respond_to?(:services)
|
48
|
+
@context = object
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def default_callbacks
|
53
|
+
require 'hydramata/core/named_callbacks'
|
54
|
+
NamedCallbacks.new
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'active_support/core_ext/array/wrap'
|
2
|
+
|
3
|
+
module Hydramata
|
4
|
+
module Core
|
5
|
+
# Responsible for handling the translation via diminishing specificity.
|
6
|
+
class Translator
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def translate(key, options = {})
|
10
|
+
new(options).translate(key, options)
|
11
|
+
end
|
12
|
+
alias_method :t, :translate
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :base_scope, :translation_service, :translation_service_error
|
16
|
+
def initialize(options = {})
|
17
|
+
self.base_scope = options.fetch(:base_scope) { default_base_scope }
|
18
|
+
@translation_service = options.fetch(:translation_service) { default_translation_service }
|
19
|
+
@translation_service_error = options.fetch(:translation_service_error) { default_translation_service_error }
|
20
|
+
end
|
21
|
+
|
22
|
+
def translate(key, options = {})
|
23
|
+
translate_key_for_specific_scopes(key, options) || translate_key_for_general_case(key, options)
|
24
|
+
end
|
25
|
+
alias_method :t, :translate
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def translate_key_for_specific_scopes(key, options = {})
|
30
|
+
return nil unless scopes = options[:scopes]
|
31
|
+
returning_value = nil
|
32
|
+
Array.wrap(scopes).each do |scope|
|
33
|
+
begin
|
34
|
+
options_to_use = options.merge(scope: base_scope + Array.wrap(scope), raise: true)
|
35
|
+
options_to_use.delete(:scopes)
|
36
|
+
options_to_use.delete(:default)
|
37
|
+
returning_value = translation_service.translate(key, options_to_use)
|
38
|
+
break
|
39
|
+
rescue *translation_service_error => e
|
40
|
+
STDOUT.puts(e) if ENV['DEBUG']
|
41
|
+
next
|
42
|
+
end
|
43
|
+
end
|
44
|
+
returning_value
|
45
|
+
end
|
46
|
+
|
47
|
+
def translate_key_for_general_case(key, options = {})
|
48
|
+
options_to_use = options.merge(scope: base_scope)
|
49
|
+
options_to_use.delete(:scopes)
|
50
|
+
translation_service.translate(key, options_to_use)
|
51
|
+
end
|
52
|
+
|
53
|
+
def base_scope=(values)
|
54
|
+
@base_scope = Array.wrap(values)
|
55
|
+
end
|
56
|
+
|
57
|
+
def default_base_scope
|
58
|
+
['hydramata', 'core']
|
59
|
+
end
|
60
|
+
|
61
|
+
def default_translation_service_error
|
62
|
+
require 'i18n/exceptions'
|
63
|
+
I18n::ArgumentError
|
64
|
+
end
|
65
|
+
|
66
|
+
def default_translation_service
|
67
|
+
require 'i18n'
|
68
|
+
I18n
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'active_support/lazy_load_hooks'
|
2
|
+
require 'active_support/dependencies/autoload'
|
3
|
+
module Hydramata
|
4
|
+
# The Services class is a dumping ground for methods. These methods are
|
5
|
+
# exposed to an application's context (i.e. a controller).
|
6
|
+
#
|
7
|
+
# It is the application's interface between the logic of the controller/
|
8
|
+
# request handling and the construction of objects.
|
9
|
+
#
|
10
|
+
# This class has been constructed such that other engines can inject
|
11
|
+
# behavior into Services using the ActiveSupport.on_load method.
|
12
|
+
#
|
13
|
+
# @see Runner
|
14
|
+
class Services
|
15
|
+
def initialize(context)
|
16
|
+
@context = context
|
17
|
+
end
|
18
|
+
attr_reader :context
|
19
|
+
end
|
20
|
+
ActiveSupport.run_load_hooks(:hydramata_services, Services)
|
21
|
+
end
|
data/script/analyzer.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
require 'sexp_processor'
|
5
|
+
require 'ruby_parser'
|
6
|
+
require 'byebug'
|
7
|
+
require 'rake'
|
8
|
+
require 'set'
|
9
|
+
|
10
|
+
class Collector
|
11
|
+
attr_reader :namespace
|
12
|
+
def initialize(namespace)
|
13
|
+
@namespace = namespace
|
14
|
+
@storage = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def push(class_stack, collaborator)
|
18
|
+
klass = register(class_stack)
|
19
|
+
@storage[klass] << collaborator
|
20
|
+
end
|
21
|
+
|
22
|
+
def register(class_stack)
|
23
|
+
klass = class_stack.reverse[0..-1].collect(&:to_s).join('::')
|
24
|
+
@storage[klass] ||= Set.new
|
25
|
+
klass
|
26
|
+
end
|
27
|
+
|
28
|
+
def render
|
29
|
+
puts %(digraph "G" {)
|
30
|
+
puts %( label="#{namespace}") if namespace
|
31
|
+
@storage.each do |klass, collaborators|
|
32
|
+
if klass.strip != '' || collaborators.any? {|c| c =~ /\A#{namespace}/ }
|
33
|
+
puts render_node(klass)
|
34
|
+
collaborators.each do |collaborator|
|
35
|
+
if @storage.detect do |some_class, _|
|
36
|
+
if some_class =~ /\A#{namespace}(::\w+)*::#{collaborator}\Z/
|
37
|
+
render_node(some_class)
|
38
|
+
render_edge(klass, some_class)
|
39
|
+
true
|
40
|
+
else
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
else
|
45
|
+
if collaborator =~ /\A#{namespace}/
|
46
|
+
render_node(collaborator)
|
47
|
+
render_edge(klass, collaborator)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
puts %(})
|
54
|
+
end
|
55
|
+
|
56
|
+
def render_node(klass)
|
57
|
+
puts %( #{to_dot_name(klass)}[label="#{klass}"])
|
58
|
+
end
|
59
|
+
|
60
|
+
def render_edge(from, to)
|
61
|
+
puts %( #{to_dot_name(from)} -> #{to_dot_name(to)})
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_dot_name(str)
|
65
|
+
str.gsub(/[\W:]+/,'_')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class DependencyAnalyzer < MethodBasedSexpProcessor
|
70
|
+
|
71
|
+
attr_reader :collector
|
72
|
+
|
73
|
+
def initialize(collector = Collector.new)
|
74
|
+
super()
|
75
|
+
@collector = collector
|
76
|
+
end
|
77
|
+
|
78
|
+
def process_colon2(exp)
|
79
|
+
klass = classify_colon2(exp).join("::")
|
80
|
+
collector.push(class_stack, klass)
|
81
|
+
return exp
|
82
|
+
end
|
83
|
+
|
84
|
+
def process_module(exp)
|
85
|
+
super(exp)
|
86
|
+
collector.register(class_stack)
|
87
|
+
return exp
|
88
|
+
end
|
89
|
+
|
90
|
+
def process_dfn(exp)
|
91
|
+
collector.register(class_stack)
|
92
|
+
return exp
|
93
|
+
end
|
94
|
+
|
95
|
+
def process_const(exp)
|
96
|
+
collaborator = exp[1]
|
97
|
+
collector.push(class_stack, collaborator.to_s)
|
98
|
+
return s(:const, collaborator)
|
99
|
+
end
|
100
|
+
|
101
|
+
def classify_colon2(exp, returning = [])
|
102
|
+
returning.unshift(exp[2]) if exp[2]
|
103
|
+
if exp[1].is_a?(Sexp)
|
104
|
+
classify_colon2(exp[1], returning)
|
105
|
+
else
|
106
|
+
returning.unshift(exp[1])
|
107
|
+
end
|
108
|
+
return returning
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
if __FILE__ == $0
|
114
|
+
collaborator = Collector.new('Hydramata::Core')
|
115
|
+
analyzer = DependencyAnalyzer.new(collaborator)
|
116
|
+
FileList['app/**/*.rb', 'lib/**/*.rb'].each do |filename|
|
117
|
+
# filename = '/Users/jfriesen/Repositories/hydramata-work/app/parsers/hydramata/core/predicate_parsers/simple_parser.rb'
|
118
|
+
file_content = File.read(filename)
|
119
|
+
parsed_file = RubyParser.for_current_ruby.parse(file_content)
|
120
|
+
# break
|
121
|
+
analyzer.process(parsed_file)
|
122
|
+
end
|
123
|
+
collaborator.render
|
124
|
+
end
|
data/script/fast_specs
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
# A helper function for answering: Does this spec run fast?
|
6
|
+
module Fast
|
7
|
+
module_function
|
8
|
+
def spec?(fn)
|
9
|
+
open(fn) { |f| f.gets =~ /spec_fast_helper/ }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
fast_specs = FileList['spec/**/*_spec.rb'].select do |fn|
|
14
|
+
Fast.spec?(fn)
|
15
|
+
end
|
16
|
+
|
17
|
+
if fast_specs.any?
|
18
|
+
system "rspec #{fast_specs}"
|
19
|
+
else
|
20
|
+
puts 'Unable to find any fast specs'
|
21
|
+
exit(-1)
|
22
|
+
end
|