riveter 0.0.1
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/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +17 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +147 -0
- data/LICENSE.txt +23 -0
- data/README.md +77 -0
- data/Rakefile +7 -0
- data/app/helpers/riveter/command_form_helper.rb +15 -0
- data/app/helpers/riveter/enquiry_form_helper.rb +16 -0
- data/app/helpers/riveter/query_filter_form_helper.rb +16 -0
- data/config/locales/forms.en.yml +25 -0
- data/config/locales/validators.en.yml +26 -0
- data/init.rb +25 -0
- data/lib/generators/erb/TODO +1 -0
- data/lib/generators/haml/command_controller/USAGE +0 -0
- data/lib/generators/haml/command_controller/command_controller_generator.rb +56 -0
- data/lib/generators/haml/command_controller/templates/new.html.haml +26 -0
- data/lib/generators/haml/enquiry_controller/USAGE +0 -0
- data/lib/generators/haml/enquiry_controller/enquiry_controller_generator.rb +56 -0
- data/lib/generators/haml/enquiry_controller/templates/index.html.haml +57 -0
- data/lib/generators/riveter/command/USAGE +0 -0
- data/lib/generators/riveter/command/command_generator.rb +55 -0
- data/lib/generators/riveter/command/templates/command.rb +40 -0
- data/lib/generators/riveter/command/templates/commands.en.yml +57 -0
- data/lib/generators/riveter/command/templates/module.rb +4 -0
- data/lib/generators/riveter/command_controller/USAGE +0 -0
- data/lib/generators/riveter/command_controller/command_controller_generator.rb +40 -0
- data/lib/generators/riveter/command_controller/templates/command_controller.rb +18 -0
- data/lib/generators/riveter/command_controller/templates/module.rb +4 -0
- data/lib/generators/riveter/enquiry/USAGE +0 -0
- data/lib/generators/riveter/enquiry/enquiry_generator.rb +29 -0
- data/lib/generators/riveter/enquiry/templates/enquiry.rb +11 -0
- data/lib/generators/riveter/enquiry/templates/module.rb +4 -0
- data/lib/generators/riveter/enquiry_controller/USAGE +0 -0
- data/lib/generators/riveter/enquiry_controller/enquiry_controller_generator.rb +34 -0
- data/lib/generators/riveter/enquiry_controller/templates/enquiry_controller.rb +9 -0
- data/lib/generators/riveter/enquiry_controller/templates/module.rb +4 -0
- data/lib/generators/riveter/enum/USAGE +41 -0
- data/lib/generators/riveter/enum/enum_generator.rb +51 -0
- data/lib/generators/riveter/enum/templates/enum.rb +17 -0
- data/lib/generators/riveter/enum/templates/enums.en.yml +35 -0
- data/lib/generators/riveter/enum/templates/module.rb +4 -0
- data/lib/generators/riveter/install/USAGE +0 -0
- data/lib/generators/riveter/install/install_generator.rb +14 -0
- data/lib/generators/riveter/presenter/USAGE +0 -0
- data/lib/generators/riveter/presenter/presenter_generator.rb +20 -0
- data/lib/generators/riveter/presenter/templates/module.rb +4 -0
- data/lib/generators/riveter/presenter/templates/presenter.rb +7 -0
- data/lib/generators/riveter/query/USAGE +22 -0
- data/lib/generators/riveter/query/query_generator.rb +20 -0
- data/lib/generators/riveter/query/templates/module.rb +4 -0
- data/lib/generators/riveter/query/templates/query.rb +31 -0
- data/lib/generators/riveter/query_filter/USAGE +0 -0
- data/lib/generators/riveter/query_filter/query_filter_generator.rb +52 -0
- data/lib/generators/riveter/query_filter/templates/module.rb +4 -0
- data/lib/generators/riveter/query_filter/templates/query_filter.rb +40 -0
- data/lib/generators/riveter/query_filter/templates/query_filters.en.yml +49 -0
- data/lib/generators/riveter/service/USAGE +0 -0
- data/lib/generators/riveter/service/service_generator.rb +20 -0
- data/lib/generators/riveter/service/templates/module.rb +4 -0
- data/lib/generators/riveter/service/templates/service.rb +12 -0
- data/lib/generators/riveter/worker/USAGE +0 -0
- data/lib/generators/riveter/worker/templates/module.rb +4 -0
- data/lib/generators/riveter/worker/templates/worker.rb +7 -0
- data/lib/generators/riveter/worker/worker_generator.rb +20 -0
- data/lib/generators/rspec/command/USAGE +0 -0
- data/lib/generators/rspec/command/command_generator.rb +11 -0
- data/lib/generators/rspec/command/templates/command_spec.rb +8 -0
- data/lib/generators/rspec/command_controller/USAGE +0 -0
- data/lib/generators/rspec/command_controller/command_controller_generator.rb +21 -0
- data/lib/generators/rspec/command_controller/templates/command_controller_spec.rb +70 -0
- data/lib/generators/rspec/enquiry/USAGE +0 -0
- data/lib/generators/rspec/enquiry/enquiry_generator.rb +11 -0
- data/lib/generators/rspec/enquiry/templates/enquiry_spec.rb +69 -0
- data/lib/generators/rspec/enquiry_controller/USAGE +0 -0
- data/lib/generators/rspec/enquiry_controller/enquiry_controller_generator.rb +16 -0
- data/lib/generators/rspec/enquiry_controller/templates/enquiry_controller_spec.rb +32 -0
- data/lib/generators/rspec/enum/USAGE +0 -0
- data/lib/generators/rspec/enum/enum_generator.rb +11 -0
- data/lib/generators/rspec/enum/templates/enum_spec.rb +8 -0
- data/lib/generators/rspec/presenter/USAGE +0 -0
- data/lib/generators/rspec/presenter/presenter_generator.rb +11 -0
- data/lib/generators/rspec/presenter/templates/presenter_spec.rb +8 -0
- data/lib/generators/rspec/query/USAGE +0 -0
- data/lib/generators/rspec/query/query_generator.rb +11 -0
- data/lib/generators/rspec/query/templates/query_spec.rb +41 -0
- data/lib/generators/rspec/query_filter/USAGE +0 -0
- data/lib/generators/rspec/query_filter/query_filter_generator.rb +11 -0
- data/lib/generators/rspec/query_filter/templates/query_filter_spec.rb +8 -0
- data/lib/generators/rspec/service/USAGE +0 -0
- data/lib/generators/rspec/service/service_generator.rb +11 -0
- data/lib/generators/rspec/service/templates/service_spec.rb +8 -0
- data/lib/generators/rspec/worker/USAGE +0 -0
- data/lib/generators/rspec/worker/templates/worker_spec.rb +8 -0
- data/lib/generators/rspec/worker/worker_generator.rb +11 -0
- data/lib/generators/test_unit/TODO +1 -0
- data/lib/riveter/associated_type_registry.rb +63 -0
- data/lib/riveter/attribute_default_values.rb +67 -0
- data/lib/riveter/attributes.rb +443 -0
- data/lib/riveter/booleaness_validator.rb +20 -0
- data/lib/riveter/command.rb +59 -0
- data/lib/riveter/command_controller.rb +93 -0
- data/lib/riveter/command_routes.rb +73 -0
- data/lib/riveter/core_extensions.rb +246 -0
- data/lib/riveter/email_validator.rb +20 -0
- data/lib/riveter/enquiry.rb +137 -0
- data/lib/riveter/enquiry_controller.rb +80 -0
- data/lib/riveter/enquiry_routes.rb +69 -0
- data/lib/riveter/enumerated.rb +107 -0
- data/lib/riveter/errors.rb +11 -0
- data/lib/riveter/form_builder_extensions.rb +21 -0
- data/lib/riveter/hash_with_dependency.rb +12 -0
- data/lib/riveter/presenter.rb +73 -0
- data/lib/riveter/query.rb +45 -0
- data/lib/riveter/query_filter.rb +22 -0
- data/lib/riveter/rails/engine.rb +6 -0
- data/lib/riveter/rails/railtie.rb +50 -0
- data/lib/riveter/service.rb +45 -0
- data/lib/riveter/spec_helper.rb +55 -0
- data/lib/riveter/tasks/.keep +0 -0
- data/lib/riveter/version.rb +3 -0
- data/lib/riveter/worker.rb +20 -0
- data/lib/riveter.rb +47 -0
- data/riveter.gemspec +40 -0
- data/spec/examples/attribute_examples.rb +57 -0
- data/spec/generators/haml/command_controller/command_controller_generator_spec.rb +34 -0
- data/spec/generators/haml/enquiry_controller/enquiry_controller_generator_spec.rb +34 -0
- data/spec/generators/riveter/command/command_generator_spec.rb +58 -0
- data/spec/generators/riveter/command_controller/command_controller_generator_spec.rb +0 -0
- data/spec/generators/riveter/enquiry/enquiry_generator_spec.rb +0 -0
- data/spec/generators/riveter/query_filter/query_filter_generator_spec.rb +58 -0
- data/spec/riveter/associated_type_registry_spec.rb +158 -0
- data/spec/riveter/attribute_default_value_spec.rb +69 -0
- data/spec/riveter/attributes_spec.rb +228 -0
- data/spec/riveter/command_controller_spec.rb +116 -0
- data/spec/riveter/command_routes_spec.rb +116 -0
- data/spec/riveter/command_spec.rb +66 -0
- data/spec/riveter/core_extensions_spec.rb +209 -0
- data/spec/riveter/enquiry_controller_spec.rb +128 -0
- data/spec/riveter/enquiry_routes_spec.rb +101 -0
- data/spec/riveter/enquiry_spec.rb +299 -0
- data/spec/riveter/enumerated_spec.rb +47 -0
- data/spec/riveter/form_builder_extensions_spec.rb +28 -0
- data/spec/riveter/presenter_spec.rb +131 -0
- data/spec/riveter/query_filter_spec.rb +19 -0
- data/spec/riveter/query_spec.rb +72 -0
- data/spec/riveter/service_spec.rb +49 -0
- data/spec/riveter/spec_helper_spec.rb +21 -0
- data/spec/riveter/worker_spec.rb +11 -0
- data/spec/spec_helper.rb +54 -0
- data/spec/support/test_associated_class.rb +2 -0
- data/spec/support/test_class_with_attributes.rb +17 -0
- data/spec/support/test_command.rb +4 -0
- data/spec/support/test_command_controller.rb +12 -0
- data/spec/support/test_command_routes.rb +3 -0
- data/spec/support/test_enquiry.rb +7 -0
- data/spec/support/test_enquiry_controller.rb +12 -0
- data/spec/support/test_enquiry_routes.rb +3 -0
- data/spec/support/test_enum.rb +8 -0
- data/spec/support/test_form_builder.rb +3 -0
- data/spec/support/test_model.rb +2 -0
- data/spec/support/test_model_with_attribute_default_values.rb +29 -0
- data/spec/support/test_presenter.rb +2 -0
- data/spec/support/test_query.rb +5 -0
- data/spec/support/test_query_filter.rb +4 -0
- data/spec/support/test_service.rb +7 -0
- data/spec/support/validate_booleaness_of_matcher.rb +17 -0
- data/spec/support/validate_timeliness_of_matcher.rb +17 -0
- data/spec/support/validator_detector.rb +48 -0
- metadata +487 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'action_dispatch'
|
|
2
|
+
|
|
3
|
+
module Riveter
|
|
4
|
+
module EnquiryRoutes
|
|
5
|
+
|
|
6
|
+
#
|
|
7
|
+
# defines a route for the given enquiry
|
|
8
|
+
#
|
|
9
|
+
# by convention, the word "enquiry" is omitted
|
|
10
|
+
# from the name of the enquiry
|
|
11
|
+
#
|
|
12
|
+
# options include:
|
|
13
|
+
#
|
|
14
|
+
# :path overrides the path used.
|
|
15
|
+
# by default it is "<enquiry>_enquiry".
|
|
16
|
+
# E.g. for :active_portfolios the path is 'active_portfolios'
|
|
17
|
+
#
|
|
18
|
+
# :controller overrides the controller used.
|
|
19
|
+
# by default it is "<enquiry>_enquiry_controller"
|
|
20
|
+
#
|
|
21
|
+
# :as overrides the name of the route generated.
|
|
22
|
+
# by default it is "<enquiry>_enquiry"
|
|
23
|
+
#
|
|
24
|
+
# :action overrides the action name.
|
|
25
|
+
# by default is is ":index"
|
|
26
|
+
#
|
|
27
|
+
# E.g.
|
|
28
|
+
#
|
|
29
|
+
# enquiry :active_portfolios
|
|
30
|
+
#
|
|
31
|
+
# creates a route 'active_portfolios' named `active_portfolios_enquiry` to the
|
|
32
|
+
# `ActivePortfoliosEnquiryController` controller for the 'index' action
|
|
33
|
+
#
|
|
34
|
+
# enquiry :active_portfolios, :as => 'recent_portfolios'
|
|
35
|
+
#
|
|
36
|
+
# creates a route 'active_portfolios' named `recent_portfolios` to the
|
|
37
|
+
# `ActivePortfoliosEnquiryController` controller for the 'index' action
|
|
38
|
+
#
|
|
39
|
+
# enquiry :active_portfolios, :path => '/all_your_portfolios'
|
|
40
|
+
#
|
|
41
|
+
# creates a route 'all_your_portfolios' named `active_portfolios_enquiry` to the
|
|
42
|
+
# `ActivePortfoliosEnquiryController` controller for the 'index' action
|
|
43
|
+
#
|
|
44
|
+
# enquiry :active_portfolios, :controller => 'my_portfolios_controller'
|
|
45
|
+
#
|
|
46
|
+
# creates a route 'active_portfolios' named `active_portfolios_enquiry` to the
|
|
47
|
+
# `MyPortfoliosController` controller for the 'index' action
|
|
48
|
+
#
|
|
49
|
+
def enquiry(enquiry, options={})
|
|
50
|
+
raise ArgumentError, 'Expects a symbol for the enquiry.' unless enquiry.is_a?(Symbol)
|
|
51
|
+
|
|
52
|
+
path = options.delete(:path) || enquiry.to_s
|
|
53
|
+
action = options.delete(:action) || :index
|
|
54
|
+
|
|
55
|
+
options = {
|
|
56
|
+
:controller => :"#{enquiry}_enquiry",
|
|
57
|
+
:as => :"#{enquiry}_enquiry"
|
|
58
|
+
}.merge(options)
|
|
59
|
+
|
|
60
|
+
# define GET 'index' route
|
|
61
|
+
get path, options.merge(:action => action)
|
|
62
|
+
|
|
63
|
+
# define POST 'index' route
|
|
64
|
+
post path, options.merge(:action => action, :as => nil)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
ActionDispatch::Routing::Mapper.send :include, Riveter::EnquiryRoutes
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
module Riveter
|
|
2
|
+
module Enumerated
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
|
|
7
|
+
const_names = self.constants(false)
|
|
8
|
+
const_values = const_names.collect {|name| self.const_get(name) }
|
|
9
|
+
|
|
10
|
+
# create hashes for decoding names and values
|
|
11
|
+
const_value_lookup ||= const_names.inject({}) {|list, name|
|
|
12
|
+
list[name] = self.const_get(name)
|
|
13
|
+
list
|
|
14
|
+
}.with_indifferent_access
|
|
15
|
+
|
|
16
|
+
const_name_lookup ||= const_names.inject({}) {|list, name|
|
|
17
|
+
list[self.const_get(name)] = name
|
|
18
|
+
list
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# define helper methods
|
|
22
|
+
|
|
23
|
+
# returns an array of the constant names as symbols
|
|
24
|
+
define_singleton_method :names do
|
|
25
|
+
const_names
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# returns an array of constant values
|
|
29
|
+
define_singleton_method :all do
|
|
30
|
+
const_values
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# given a value, returns the name of the constant as a symbol
|
|
34
|
+
define_singleton_method :name_for do |value|
|
|
35
|
+
const_name_lookup[value]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# given a name, returns the value of the constant
|
|
39
|
+
# accepts a string or symbol for the constants name
|
|
40
|
+
define_singleton_method :value_for do |name|
|
|
41
|
+
const_value_lookup[name]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# returns the human name for the given constant name or value
|
|
45
|
+
# it uses the locale to lookup the translation
|
|
46
|
+
# and defaults to the capitalized name of the constant
|
|
47
|
+
define_singleton_method :human_name_for do |name_or_value, options={}|
|
|
48
|
+
const_name = name_or_value.is_a?(Symbol) ?
|
|
49
|
+
name_or_value :
|
|
50
|
+
value_for(name_or_value)
|
|
51
|
+
|
|
52
|
+
options = {
|
|
53
|
+
:scope => [:enums, self.to_s.underscore],
|
|
54
|
+
:default => const_name.to_s.titleize
|
|
55
|
+
}.merge!(options)
|
|
56
|
+
|
|
57
|
+
I18n.translate(const_name, options)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# defines the "All" constant
|
|
61
|
+
# which is array like object that can be used to loop
|
|
62
|
+
# over the set of constants and provides some helper methods
|
|
63
|
+
self.const_set :All, Enumeration.new(self, const_values)
|
|
64
|
+
|
|
65
|
+
# for use within form select inputs
|
|
66
|
+
define_singleton_method :collection do
|
|
67
|
+
self.const_get(:All).collect {|m| [m.human, m.value] }
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
module ClassMethods
|
|
72
|
+
def human(options={})
|
|
73
|
+
options = {
|
|
74
|
+
:scope => [:enums, self.to_s.underscore],
|
|
75
|
+
:default => self.name.titleize
|
|
76
|
+
}.merge!(options)
|
|
77
|
+
|
|
78
|
+
I18n.translate(:human, options)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class Enumeration < Array
|
|
83
|
+
attr_reader :enum
|
|
84
|
+
|
|
85
|
+
delegate :names, :values, :human, :to => :enum
|
|
86
|
+
|
|
87
|
+
def initialize(enum, values)
|
|
88
|
+
@enum = enum
|
|
89
|
+
super(values.collect {|value| Member.new(enum, value) })
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
class Member
|
|
94
|
+
attr_reader :name, :value
|
|
95
|
+
|
|
96
|
+
def initialize(enum, value)
|
|
97
|
+
@enum = enum
|
|
98
|
+
@name = enum.name_for(value)
|
|
99
|
+
@value = value
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def human(options={})
|
|
103
|
+
@enum.human_name_for(name, options)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'action_view'
|
|
2
|
+
|
|
3
|
+
module Riveter
|
|
4
|
+
module FormBuilderExtensions
|
|
5
|
+
|
|
6
|
+
def search
|
|
7
|
+
submit I18n.translate(:search, :scope => [:forms]), :name => :search
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def reset
|
|
11
|
+
submit I18n.translate(:reset, :scope => [:forms]), :name => :reset
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module ActionView::Helpers
|
|
18
|
+
class FormBuilder
|
|
19
|
+
include Riveter::FormBuilderExtensions
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Riveter
|
|
2
|
+
# See http://ruby-doc.org/stdlib-2.0/libdoc/tsort/rdoc/TSort.html for details
|
|
3
|
+
class HashWithDependency < Hash
|
|
4
|
+
include TSort
|
|
5
|
+
|
|
6
|
+
alias tsort_each_node each_key
|
|
7
|
+
|
|
8
|
+
def tsort_each_child(node, &block)
|
|
9
|
+
fetch(node).each(&block)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module Riveter
|
|
2
|
+
module Presenter
|
|
3
|
+
module Object
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
def to_presenter(klass)
|
|
7
|
+
raise ArgumentError, 'klass argument cannot be nil' if klass.nil?
|
|
8
|
+
raise ArgumentError, "#{klass} is not a valid presenter class" unless klass <= Presenter::Base
|
|
9
|
+
klass.new(self)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module Enumerator
|
|
14
|
+
extend ActiveSupport::Concern
|
|
15
|
+
|
|
16
|
+
def with_presenter(klass, &block)
|
|
17
|
+
raise ArgumentError, 'klass argument cannot be nil' if klass.nil?
|
|
18
|
+
raise ArgumentError, "#{klass} is not a valid presenter class" unless klass <= Presenter::Base
|
|
19
|
+
return to_enum(__method__, klass) unless block_given?
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
# some magic!
|
|
23
|
+
# assuming that this method is used within the view
|
|
24
|
+
# the block which is supplied will be in the scope of the view
|
|
25
|
+
# therefore, getting it's binding and evaluating self will
|
|
26
|
+
# get us the view object
|
|
27
|
+
##
|
|
28
|
+
view = block.binding.eval('self')
|
|
29
|
+
is_a_view = view.is_a?(ActionView::Base)
|
|
30
|
+
|
|
31
|
+
self.each do |item|
|
|
32
|
+
yield klass.new(item, (is_a_view ? view : nil))
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class Base < SimpleDelegator
|
|
38
|
+
def item
|
|
39
|
+
__getobj__
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def initialize(item, view=nil)
|
|
43
|
+
super(item)
|
|
44
|
+
@view = view
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def method_missing(method, *args, &block)
|
|
48
|
+
return super if @view.nil?
|
|
49
|
+
|
|
50
|
+
if respond_to_without_view?(method)
|
|
51
|
+
super
|
|
52
|
+
elsif @view.respond_to?(method)
|
|
53
|
+
@view.send(method, *args, &block)
|
|
54
|
+
else
|
|
55
|
+
super
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def respond_to_with_view?(method)
|
|
60
|
+
respond_to_without_view?(method) || (!@view.nil? && @view.respond_to?(method))
|
|
61
|
+
end
|
|
62
|
+
alias_method_chain :respond_to?, :view
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class Object
|
|
68
|
+
include Riveter::Presenter::Object
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
class Enumerator
|
|
72
|
+
include Riveter::Presenter::Enumerator
|
|
73
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Riveter
|
|
2
|
+
module Query
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
attr_reader :query_filter
|
|
6
|
+
attr_reader :options
|
|
7
|
+
attr_reader :relation
|
|
8
|
+
|
|
9
|
+
def initialize(query_filter, options={})
|
|
10
|
+
@query_filter = query_filter
|
|
11
|
+
@options = options
|
|
12
|
+
@relation = build_relation(@query_filter)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# enumerates the resultset in batch mode
|
|
16
|
+
def find_each(&block)
|
|
17
|
+
relation.find_each_with_order(&block) if has_data?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# override if necessary in derived classes
|
|
21
|
+
def has_data?
|
|
22
|
+
@has_data ||= relation.count() > 0
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
protected
|
|
26
|
+
|
|
27
|
+
# override in derived classes
|
|
28
|
+
def build_relation(filter)
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# use the given filter to add conditions
|
|
32
|
+
# to produce an ActiveRelation as the query
|
|
33
|
+
#
|
|
34
|
+
# E.g. filter.page #=> Model.all.page(filter.page)
|
|
35
|
+
#
|
|
36
|
+
|
|
37
|
+
raise NotImplementedError
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# helper class
|
|
41
|
+
class Base
|
|
42
|
+
include Query
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Riveter
|
|
2
|
+
module QueryFilter
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
include Riveter::Attributes
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
alias_method :filter_name, :model_name
|
|
10
|
+
|
|
11
|
+
def i18n_scope
|
|
12
|
+
:query_filters
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# helper class
|
|
18
|
+
class Base
|
|
19
|
+
include QueryFilter
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Riveter
|
|
2
|
+
module Rails
|
|
3
|
+
class Railtie < ::Rails::Railtie
|
|
4
|
+
initializer 'riveter.initialize' do
|
|
5
|
+
require 'riveter/form_builder_extensions'
|
|
6
|
+
require 'riveter/command_routes'
|
|
7
|
+
require 'riveter/enquiry_routes'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
initializer 'riveter.set_autoload_paths', :before => :set_autoload_paths do |app|
|
|
11
|
+
config = app.config
|
|
12
|
+
|
|
13
|
+
# add paths to auto load path
|
|
14
|
+
%w{
|
|
15
|
+
commands
|
|
16
|
+
enquiries
|
|
17
|
+
enums
|
|
18
|
+
presenters
|
|
19
|
+
queries
|
|
20
|
+
query_filters
|
|
21
|
+
services
|
|
22
|
+
workers
|
|
23
|
+
}.each do |path|
|
|
24
|
+
config.autoload_paths += %W(#{config.root}/app/#{path})
|
|
25
|
+
config.autoload_paths += %W(#{config.root}/app/#{path}/concerns)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
initializer "riveter.load_services" do |app|
|
|
30
|
+
ActiveSupport.on_load :after_initialize do |app|
|
|
31
|
+
#
|
|
32
|
+
# services need to be loaded manually since they aren't referenced
|
|
33
|
+
# directly and therefore cannot be autoloaded
|
|
34
|
+
#
|
|
35
|
+
# also, when the class is loaded, it registers itself as the service for a command
|
|
36
|
+
#
|
|
37
|
+
Dir[File.join(app.config.root, 'app', 'services', '**/*_service.rb')].each {|file| require file }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
console do
|
|
42
|
+
# TODO
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
rake_tasks do
|
|
46
|
+
Dir[File.join(File.dirname(__FILE__), 'tasks/*.rake')].each { |file| load file }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Riveter
|
|
2
|
+
module Service
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
include AssociatedTypeRegistry
|
|
5
|
+
|
|
6
|
+
module ClassMethods
|
|
7
|
+
def register_as_handler_for(command_type)
|
|
8
|
+
register_type self, command_type
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# override in derived classes
|
|
13
|
+
def perform(command, *args)
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# use the given command's attributes to perform the action
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
raise NotImplementedError
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# helper class
|
|
23
|
+
class Base
|
|
24
|
+
include Service
|
|
25
|
+
|
|
26
|
+
class << self
|
|
27
|
+
def inherited(klass)
|
|
28
|
+
#
|
|
29
|
+
# attempt to get the name of the command
|
|
30
|
+
# from the derived classes name and register
|
|
31
|
+
# it as the service handler for that command
|
|
32
|
+
#
|
|
33
|
+
# e.g. CreatePortfolioCommand ==> CreatePortfolioService
|
|
34
|
+
#
|
|
35
|
+
command_type = klass.name.gsub(/Service$/, 'Command').constantize rescue nil
|
|
36
|
+
register_type klass, command_type unless command_type.nil?
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# NOTE: associated commands will be registered on this class!
|
|
41
|
+
# use the respective resolve methods with the Riveter::Service::Base in this case
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# helpers for use in testing
|
|
2
|
+
|
|
3
|
+
module Mock
|
|
4
|
+
class Block
|
|
5
|
+
def to_proc
|
|
6
|
+
lambda { |*args| call(*args) }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# the call method must be provided by in specs
|
|
10
|
+
# E.g. using `expect(mock_block_instance).to receive(:call)` to assert that the "block" gets called
|
|
11
|
+
def call
|
|
12
|
+
raise NotImplementedError, "Expecting `call` method to have an expectation defined to assert."
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module Valid
|
|
17
|
+
def valid?
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module Invalid
|
|
23
|
+
def valid?
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class ValidCommand < Riveter::Command::Base
|
|
29
|
+
include Valid
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class InvalidCommand < Riveter::Command::Base
|
|
33
|
+
include Invalid
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class ValidQueryFilter < Riveter::QueryFilter::Base
|
|
37
|
+
include Valid
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class InvalidQueryFilter < Riveter::QueryFilter::Base
|
|
41
|
+
include Invalid
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class QueryWithData < Riveter::Query::Base
|
|
45
|
+
def has_data?
|
|
46
|
+
true
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class QueryWithoutData < Riveter::Query::Base
|
|
51
|
+
def has_data?
|
|
52
|
+
false
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Riveter
|
|
2
|
+
module Worker
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
# TODO: define mixed in methods
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
# TODO: define class methods
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# TODO: define instance methods
|
|
14
|
+
|
|
15
|
+
# helper class
|
|
16
|
+
class Base
|
|
17
|
+
include Worker
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/riveter.rb
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require "riveter/version"
|
|
2
|
+
|
|
3
|
+
require 'active_model'
|
|
4
|
+
require 'active_record'
|
|
5
|
+
require 'active_support'
|
|
6
|
+
require 'validates_timeliness'
|
|
7
|
+
|
|
8
|
+
require 'active_support/core_ext'
|
|
9
|
+
require 'active_support/inflector'
|
|
10
|
+
require 'active_support/inflector'
|
|
11
|
+
|
|
12
|
+
module Riveter
|
|
13
|
+
autoload :AttributeDefaultValues, 'riveter/attribute_default_values'
|
|
14
|
+
autoload :AssociatedTypeRegistry, 'riveter/associated_type_registry'
|
|
15
|
+
autoload :Attributes, 'riveter/attributes'
|
|
16
|
+
autoload :Command, 'riveter/command'
|
|
17
|
+
autoload :CommandController, 'riveter/command_controller'
|
|
18
|
+
autoload :Enquiry, 'riveter/enquiry'
|
|
19
|
+
autoload :EnquiryController, 'riveter/enquiry_controller'
|
|
20
|
+
autoload :Enumerated, 'riveter/enumerated'
|
|
21
|
+
autoload :HashWithDependency, 'riveter/hash_with_dependency'
|
|
22
|
+
autoload :Presenter, 'riveter/presenter'
|
|
23
|
+
autoload :Query, 'riveter/query'
|
|
24
|
+
autoload :QueryFilter, 'riveter/query_filter'
|
|
25
|
+
autoload :Service, 'riveter/service'
|
|
26
|
+
autoload :Worker, 'riveter/worker'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# add autoload's for validators
|
|
30
|
+
module ActiveModel
|
|
31
|
+
module Validations
|
|
32
|
+
autoload :BooleanessValidator, 'riveter/booleaness_validator'
|
|
33
|
+
autoload :EmailValidator, 'riveter/email_validator'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
require 'riveter/errors'
|
|
38
|
+
require 'riveter/core_extensions'
|
|
39
|
+
|
|
40
|
+
# Rails bits...
|
|
41
|
+
require 'riveter/rails/railtie' if defined?(::Rails::Railtie)
|
|
42
|
+
require 'riveter/rails/engine' if defined?(::Rails)
|
|
43
|
+
|
|
44
|
+
# include locale in load path
|
|
45
|
+
Dir[File.join(File.dirname(__FILE__), '*.yml')].each do |file|
|
|
46
|
+
I18n.load_path << file
|
|
47
|
+
end
|
data/riveter.gemspec
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'riveter/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = 'riveter'
|
|
8
|
+
spec.version = Riveter::VERSION
|
|
9
|
+
spec.authors = ['Chris Stefano']
|
|
10
|
+
spec.email = ['virtualstaticvoid@gmail.com']
|
|
11
|
+
spec.summary = %q{Provides several useful patterns, packaged in a gem, for use in Rails.}
|
|
12
|
+
spec.description = %q{Provides several useful patterns, such as Enumerated, Command, Enquiry, Query, QueryFilter, Service, Presenter and Worker, packaged in a gem, for use in Rails and other Ruby applications.}
|
|
13
|
+
spec.homepage = 'https://github.com/virtualstaticvoid/riveter'
|
|
14
|
+
spec.license = 'MIT'
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ['lib']
|
|
20
|
+
|
|
21
|
+
spec.required_ruby_version = '>= 2.0.0'
|
|
22
|
+
|
|
23
|
+
spec.add_dependency 'railties', '~> 4.0.0'
|
|
24
|
+
spec.add_dependency 'actionpack'
|
|
25
|
+
spec.add_dependency 'activemodel'
|
|
26
|
+
spec.add_dependency 'activerecord'
|
|
27
|
+
spec.add_dependency 'activesupport'
|
|
28
|
+
spec.add_dependency 'validates_timeliness'
|
|
29
|
+
|
|
30
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
|
31
|
+
spec.add_development_dependency 'rake'
|
|
32
|
+
spec.add_development_dependency 'rails', '~> 4.0.5'
|
|
33
|
+
spec.add_development_dependency 'haml-rails'
|
|
34
|
+
spec.add_development_dependency 'rspec-rails'
|
|
35
|
+
spec.add_development_dependency 'shoulda-matchers', '~> 2.6.1'
|
|
36
|
+
spec.add_development_dependency 'ammeter'
|
|
37
|
+
spec.add_development_dependency 'simplecov', '~> 0.7.1'
|
|
38
|
+
spec.add_development_dependency 'pry'
|
|
39
|
+
spec.add_development_dependency 'pry-byebug'
|
|
40
|
+
end
|