flexite 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +12 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  6. data/app/assets/fonts/glyphicons-halflings-regular.svg +288 -0
  7. data/app/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  8. data/app/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  9. data/app/assets/fonts/glyphicons-halflings-regular.woff2 +0 -0
  10. data/app/assets/images/flexite/glyphicons-halflings-white.png +0 -0
  11. data/app/assets/images/flexite/glyphicons-halflings.png +0 -0
  12. data/app/assets/javascripts/flexite/application.js +18 -0
  13. data/app/assets/javascripts/flexite/bootstrap.min.js +7 -0
  14. data/app/assets/javascripts/flexite/common.js.erb +2 -0
  15. data/app/assets/javascripts/flexite/jquery.min.js +2 -0
  16. data/app/assets/javascripts/flexite/tree.js.erb +83 -0
  17. data/app/assets/javascripts/flexite/treeview.js +1335 -0
  18. data/app/assets/stylesheets/flexite/application.css +29 -0
  19. data/app/assets/stylesheets/flexite/bootstrap-treeview.min.css +1 -0
  20. data/app/assets/stylesheets/flexite/bootstrap.min.css +5 -0
  21. data/app/assets/stylesheets/flexite/configs.css +8 -0
  22. data/app/assets/stylesheets/flexite/entries.css +4 -0
  23. data/app/assets/stylesheets/flexite/tree.css +21 -0
  24. data/app/assets/stylesheets/scaffold.css +56 -0
  25. data/app/controllers/flexite/application_controller.rb +25 -0
  26. data/app/controllers/flexite/configs_controller.rb +61 -0
  27. data/app/controllers/flexite/entries_controller.rb +82 -0
  28. data/app/factories/flexite/base_factory.rb +7 -0
  29. data/app/factories/flexite/service_factory.rb +19 -0
  30. data/app/forms/flexite/base_form.rb +24 -0
  31. data/app/forms/flexite/config/form.rb +12 -0
  32. data/app/forms/flexite/entry/array_form.rb +11 -0
  33. data/app/forms/flexite/entry/form.rb +16 -0
  34. data/app/helpers/flexite/application_helper.rb +15 -0
  35. data/app/helpers/flexite/configs_helper.rb +4 -0
  36. data/app/helpers/flexite/entries_helper.rb +46 -0
  37. data/app/models/flexite/arr_entry.rb +35 -0
  38. data/app/models/flexite/bool_entry.rb +19 -0
  39. data/app/models/flexite/config.rb +64 -0
  40. data/app/models/flexite/entry.rb +30 -0
  41. data/app/models/flexite/int_entry.rb +13 -0
  42. data/app/models/flexite/str_entry.rb +2 -0
  43. data/app/models/flexite/sym_entry.rb +17 -0
  44. data/app/services/flexite/action_service/result.rb +44 -0
  45. data/app/services/flexite/action_service.rb +30 -0
  46. data/app/services/flexite/config/create_service.rb +25 -0
  47. data/app/services/flexite/config/update_service.rb +28 -0
  48. data/app/services/flexite/data/hash.rb +17 -0
  49. data/app/services/flexite/data/migrators/yaml.rb +62 -0
  50. data/app/services/flexite/data/new.rb +87 -0
  51. data/app/services/flexite/entry/array_create_service.rb +69 -0
  52. data/app/services/flexite/entry/array_update_service.rb +69 -0
  53. data/app/services/flexite/entry/create_service.rb +31 -0
  54. data/app/services/flexite/entry/destroy_array_entry_service.rb +25 -0
  55. data/app/services/flexite/entry/destroy_service.rb +22 -0
  56. data/app/services/flexite/entry/update_service.rb +26 -0
  57. data/app/simple_form/array_input.rb +13 -0
  58. data/app/views/flexite/application/index.html.haml +14 -0
  59. data/app/views/flexite/configs/_form.html.haml +7 -0
  60. data/app/views/flexite/configs/create.js.haml +3 -0
  61. data/app/views/flexite/configs/edit.js.haml +1 -0
  62. data/app/views/flexite/configs/index.json.erb +10 -0
  63. data/app/views/flexite/configs/new.js.haml +1 -0
  64. data/app/views/flexite/configs/update.js.haml +2 -0
  65. data/app/views/flexite/entries/_form.html.haml +11 -0
  66. data/app/views/flexite/entries/_new_array_entry_form.html.haml +7 -0
  67. data/app/views/flexite/entries/_popup.html.haml +18 -0
  68. data/app/views/flexite/entries/_types_dropdown.html.haml +8 -0
  69. data/app/views/flexite/entries/create.js.haml +4 -0
  70. data/app/views/flexite/entries/destroy.js.haml +4 -0
  71. data/app/views/flexite/entries/destroy_array_entry.js.haml +6 -0
  72. data/app/views/flexite/entries/edit.js.haml +1 -0
  73. data/app/views/flexite/entries/new.js.haml +1 -0
  74. data/app/views/flexite/entries/new_array_entry.js.haml +1 -0
  75. data/app/views/flexite/entries/select_type.js.haml +1 -0
  76. data/app/views/flexite/entries/types/_arr_entry.html.haml +19 -0
  77. data/app/views/flexite/entries/types/_bool_entry.html.haml +4 -0
  78. data/app/views/flexite/entries/types/_int_entry.html.haml +4 -0
  79. data/app/views/flexite/entries/types/_str_entry.html.haml +4 -0
  80. data/app/views/flexite/entries/types/_sym_entry.html.haml +1 -0
  81. data/app/views/flexite/entries/update.js.haml +1 -0
  82. data/app/views/flexite/shared/_messages.html.haml +5 -0
  83. data/app/views/flexite/shared/_show_flash.js.haml +5 -0
  84. data/app/views/layouts/flexite/application.html.haml +11 -0
  85. data/config/initializers/simple_form.rb +143 -0
  86. data/config/initializers/simple_form_bootstrap.rb +43 -0
  87. data/config/locales/simple_form.en.yml +26 -0
  88. data/config/routes.rb +17 -0
  89. data/db/migrate/20180503102555_create_flexite_configs.rb +14 -0
  90. data/db/migrate/20180503103109_create_flexite_entries.rb +14 -0
  91. data/lib/flexite/cached_node.rb +19 -0
  92. data/lib/flexite/configuration.rb +24 -0
  93. data/lib/flexite/engine.rb +18 -0
  94. data/lib/flexite/flexy.rb +13 -0
  95. data/lib/flexite/nodes_hash.rb +5 -0
  96. data/lib/flexite/version.rb +3 -0
  97. data/lib/flexite.rb +44 -0
  98. data/lib/tasks/flexite_tasks.rake +20 -0
  99. data/test/dummy/README.rdoc +261 -0
  100. data/test/dummy/Rakefile +7 -0
  101. data/test/dummy/app/assets/javascripts/application.js +15 -0
  102. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  103. data/test/dummy/app/controllers/application_controller.rb +3 -0
  104. data/test/dummy/app/helpers/application_helper.rb +2 -0
  105. data/test/dummy/config/application.rb +59 -0
  106. data/test/dummy/config/application.yml +599 -0
  107. data/test/dummy/config/boot.rb +10 -0
  108. data/test/dummy/config/database.yml +25 -0
  109. data/test/dummy/config/environment.rb +5 -0
  110. data/test/dummy/config/environments/development.rb +40 -0
  111. data/test/dummy/config/environments/production.rb +67 -0
  112. data/test/dummy/config/environments/test.rb +37 -0
  113. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  114. data/test/dummy/config/initializers/flexite.rb +5 -0
  115. data/test/dummy/config/initializers/inflections.rb +15 -0
  116. data/test/dummy/config/initializers/mime_types.rb +5 -0
  117. data/test/dummy/config/initializers/secret_token.rb +7 -0
  118. data/test/dummy/config/initializers/session_store.rb +8 -0
  119. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  120. data/test/dummy/config/locales/en.yml +5 -0
  121. data/test/dummy/config/routes.rb +3 -0
  122. data/test/dummy/config.ru +4 -0
  123. data/test/dummy/db/development.sqlite3 +0 -0
  124. data/test/dummy/db/schema.rb +39 -0
  125. data/test/dummy/db/seeds.rb +3 -0
  126. data/test/dummy/db/test.sqlite3 +0 -0
  127. data/test/dummy/log/development.log +86588 -0
  128. data/test/dummy/public/404.html +26 -0
  129. data/test/dummy/public/422.html +26 -0
  130. data/test/dummy/public/500.html +25 -0
  131. data/test/dummy/public/favicon.ico +0 -0
  132. data/test/dummy/script/rails +6 -0
  133. data/test/dummy/tmp/cache/assets/C67/060/sprockets%2Ffaf176441f0544dd2b51901280044b40 +0 -0
  134. data/test/dummy/tmp/cache/assets/C9D/530/sprockets%2Fdcd49c063327c12052812f41c20a8e74 +0 -0
  135. data/test/dummy/tmp/cache/assets/CA3/270/sprockets%2F502b740063f8ec15e7e12811da71c772 +0 -0
  136. data/test/dummy/tmp/cache/assets/CDC/060/sprockets%2F8ff1d307d1b36810549d0829722b7aea +0 -0
  137. data/test/dummy/tmp/cache/assets/CDE/120/sprockets%2F5fd8b3fa3724451579552aed373410ce +0 -0
  138. data/test/dummy/tmp/cache/assets/CF8/980/sprockets%2F4e5077b95460dc34d7c9d7d9880e7b47 +0 -0
  139. data/test/dummy/tmp/cache/assets/D00/4C0/sprockets%2F603c6d7b825c2f4a6422b3d4af4e6203 +0 -0
  140. data/test/dummy/tmp/cache/assets/D00/C40/sprockets%2F999847c008fb4ce26fff5607c39d8358 +0 -0
  141. data/test/dummy/tmp/cache/assets/D09/A30/sprockets%2F2a71e20a2f3544acb51956504cd8d8e9 +0 -0
  142. data/test/dummy/tmp/cache/assets/D0D/E60/sprockets%2F90ea9eaa4671ec2d76703bae31972634 +0 -0
  143. data/test/dummy/tmp/cache/assets/D2A/160/sprockets%2Fbe17d4d0be4b381500e2824bbe273d70 +0 -0
  144. data/test/dummy/tmp/cache/assets/D2E/700/sprockets%2Fb21f85e0940bbcb3a8914c9cb0b07218 +0 -0
  145. data/test/dummy/tmp/cache/assets/D39/CD0/sprockets%2F0e8f6981475e49ea9fe14698fa57e4e9 +0 -0
  146. data/test/dummy/tmp/cache/assets/D40/590/sprockets%2F181dd5673b58f1ec4c89e50028bfad60 +0 -0
  147. data/test/dummy/tmp/cache/assets/D46/870/sprockets%2Fd880bdf72c5d0009b88fda8521439dc8 +0 -0
  148. data/test/dummy/tmp/cache/assets/D48/5F0/sprockets%2Fe6a83afb2d92f4692ffb391b5285a518 +0 -0
  149. data/test/dummy/tmp/cache/assets/D4B/A20/sprockets%2Febde89014596e655c35df9c4a01ee636 +0 -0
  150. data/test/dummy/tmp/cache/assets/D54/A50/sprockets%2Ff49839d906f69fd92904ebac07a3a38e +0 -0
  151. data/test/dummy/tmp/cache/assets/D69/B50/sprockets%2F4186e2787004e19ceb0c4afed46cf04b +0 -0
  152. data/test/dummy/tmp/cache/assets/D6D/C20/sprockets%2F112e96fea93f5f1e31d2077f1cdaf283 +0 -0
  153. data/test/dummy/tmp/cache/assets/D7A/8F0/sprockets%2F8eefc5f9824d950317a5c4a2e68b3c4e +0 -0
  154. data/test/dummy/tmp/cache/assets/DB3/360/sprockets%2F24b1f98ad736884b91d6ebeb2fc68ed8 +0 -0
  155. data/test/dummy/tmp/cache/assets/DD2/E90/sprockets%2Ff01f48c96ba588d15b20dd57ed3ccb7f +0 -0
  156. data/test/dummy/tmp/cache/assets/DEE/0C0/sprockets%2Feedcd74856542eedb5ea3ab1b1502ca4 +0 -0
  157. data/test/dummy/tmp/cache/assets/DF1/210/sprockets%2Ff4fe7dba1445ba1b668aaa1bd34ca984 +0 -0
  158. data/test/dummy/tmp/cache/assets/E44/790/sprockets%2Fefb8d8ea9e97da9d675a8bfa1d5de343 +0 -0
  159. data/test/fixtures/flexite/configs.yml +7 -0
  160. data/test/fixtures/flexite/entries.yml +13 -0
  161. data/test/flexite_test.rb +7 -0
  162. data/test/functional/flexite/configs_controller_test.rb +51 -0
  163. data/test/functional/flexite/entries_controller_test.rb +51 -0
  164. data/test/integration/navigation_test.rb +10 -0
  165. data/test/test_helper.rb +15 -0
  166. data/test/unit/flexite/config_test.rb +9 -0
  167. data/test/unit/flexite/entry_test.rb +9 -0
  168. data/test/unit/helpers/flexite/configs_helper_test.rb +6 -0
  169. data/test/unit/helpers/flexite/entries_helper_test.rb +6 -0
  170. metadata +366 -0
@@ -0,0 +1,24 @@
1
+ class Flexite::BaseForm
2
+ include ActiveModel::Validations
3
+ include ActiveModel::Conversion
4
+ extend ActiveModel::Naming
5
+
6
+ attr_reader :attributes
7
+
8
+ def initialize(attributes = {})
9
+ @attributes = HashWithIndifferentAccess.new
10
+
11
+ attributes.each do |name, value|
12
+ send("#{name}=", value) rescue next
13
+ @attributes[name] = value
14
+ end
15
+ end
16
+
17
+ def persisted?
18
+ respond_to?(:id) && id.present?
19
+ end
20
+
21
+ def new_record?
22
+ !persisted?
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ require_dependency 'flexite/base_form'
2
+
3
+ module Flexite
4
+ class Config::Form < BaseForm
5
+ attr_accessor :id, :name, :config_id, :created_by, :selectable
6
+ validates :name, presence: true
7
+
8
+ def self.model_name
9
+ Config.model_name
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module Flexite
2
+ class Entry
3
+ class ArrayForm < Form
4
+ attr_accessor :entries, :new_entries
5
+
6
+ def entries
7
+ @entries ||= []
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ require_dependency 'flexite/base_form'
2
+
3
+ module Flexite
4
+ class Entry::Form < BaseForm
5
+ attr_accessor :id, :type, :value, :parent_id, :parent_type
6
+ validates :type, presence: true
7
+
8
+ def self.model_name
9
+ Entry.model_name
10
+ end
11
+
12
+ def view_type
13
+ type.demodulize.underscore
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module Flexite
2
+ module ApplicationHelper
3
+ def present(model)
4
+ unless model.respond_to?(:presenter)
5
+ raise "#{model.class.name} is not presentable"
6
+ end
7
+
8
+ yield(model.presenter(self))
9
+ end
10
+
11
+ def back_to_app
12
+ link_to "Back to #{Flexite.config.app_name}", Flexite.config.app_link, class: 'btn btn-default'
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ module Flexite
2
+ module ConfigsHelper
3
+ end
4
+ end
@@ -0,0 +1,46 @@
1
+ module Flexite
2
+ module EntriesHelper
3
+ ENTRY_TYPE_OPTIONS = [
4
+ ['String', 'Flexite::StrEntry'],
5
+ ['Symbol', 'Flexite::SymEntry'],
6
+ ['Boolean', 'Flexite::BoolEntry'],
7
+ ['Array', 'Flexite::ArrEntry'],
8
+ ['Integer', 'Flexite::IntEntry']
9
+ ].freeze
10
+
11
+ def render_entries(entries, form)
12
+ content_tag :div, id: "array-entries-#{form.options[:index]}" do
13
+ entries.each_with_index do |entry, index|
14
+ concat render_entry(entry, form, index)
15
+ end
16
+ end
17
+ end
18
+
19
+ def entry_type_select(f = nil)
20
+ if f.present?
21
+ f.select :type, options_for_select(ENTRY_TYPE_OPTIONS), {}, class: 'form-control'
22
+ else
23
+ select_tag :new_entry_type, options_for_select(ENTRY_TYPE_OPTIONS), class: 'form-control'
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def render_entry(entry, form, index)
30
+ cache entry do
31
+ entry_form = entry.class.form(entry.form_attributes)
32
+
33
+ concat(form.simple_fields_for(:entries, entry_form, index: index) do |fields|
34
+ delete_link = link_to 'Delete', destroy_array_entries_path(id: entry.id, selector: "#{fields.object_name}-#{index}-#{entry.id}"),
35
+ remote: true, method: :delete, class: 'btn btn-danger'
36
+
37
+ concat(content_tag(:div, id: "#{fields.object_name}-#{index}-#{entry.id}") do
38
+ concat fields.input :id, as: :hidden
39
+ concat fields.input :type, as: :hidden
40
+ concat render "types/#{entry_form.view_type}", f: fields, delete_link: delete_link
41
+ end)
42
+ end)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,35 @@
1
+ module Flexite
2
+ class ArrEntry < Entry
3
+ has_many :entries, as: :parent, dependent: :destroy
4
+
5
+ def value
6
+ entries.select([:id, :value, :type]).map(&:value)
7
+ end
8
+
9
+ def entry=(entry)
10
+ entries << entry
11
+ end
12
+
13
+ def form_attributes
14
+ attributes.merge(entries: form_entries)
15
+ end
16
+
17
+ def self.form(attributes = {})
18
+ Entry::ArrayForm.new(attributes)
19
+ end
20
+
21
+ def self.service(type)
22
+ "arr_entry_#{type}".to_sym
23
+ end
24
+
25
+ private
26
+
27
+ def form_entries
28
+ entries.select([:id, :value, :type, :updated_at])
29
+ end
30
+
31
+ def cast_value
32
+ # value should be blank
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ module Flexite
2
+ class BoolEntry < Entry
3
+ def value
4
+ self[:value].to_i == 1 ? true : false
5
+ end
6
+
7
+ def form
8
+ Entry::Form.new(attributes.merge(value: self[:value].to_i))
9
+ end
10
+
11
+ private
12
+
13
+ def check_value
14
+ unless [1, 0].include?(self[:value].to_i)
15
+ errors.add(:value, 'not a boolean')
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,64 @@
1
+ module Flexite
2
+ class Config < ActiveRecord::Base
3
+ attr_accessible :name
4
+ belongs_to :config, touch: true
5
+ belongs_to :owner, foreign_key: :created_by
6
+ has_one :entry, as: :parent, dependent: :destroy
7
+ has_many :configs, dependent: :destroy
8
+
9
+ scope :not_selectable, -> { select([:id, :name]).where(selectable: false) }
10
+ delegate :value, to: :entry, allow_nil: true
11
+ validates :name, uniqueness: { scope: :config_id }
12
+
13
+ def to_tree_node
14
+ {
15
+ id: id,
16
+ editHref: Engine.routes.url_helpers.edit_config_path(self),
17
+ selfHref: Engine.routes.url_helpers.config_path(self),
18
+ newHref: Engine.routes.url_helpers.new_config_config_path(self),
19
+ text: name,
20
+ dataHref: selectable ? entry_href : configs_href,
21
+ nodes: nodes,
22
+ selectable: true,
23
+ ajaxOnSelect: selectable
24
+ }
25
+ end
26
+
27
+ def self.tree_view(parent_id)
28
+ joins("LEFT JOIN #{table_name} AS configs_#{table_name} ON configs_#{table_name}.config_id = #{table_name}.id")
29
+ .joins("LEFT JOIN #{Entry.table_name} ON #{Entry.table_name}.parent_id = #{table_name}.id AND #{Entry.table_name}.parent_type = '#{model_name}'")
30
+ .select(["#{table_name}.id", "#{table_name}.selectable", "#{table_name}.name", "#{table_name}.updated_at", "COUNT(configs_#{table_name}.id) as nodes_count", "#{Entry.table_name}.id AS entry_id"])
31
+ .where(config_id: parent_id).group("#{table_name}.id")
32
+ end
33
+
34
+ def nodes_count
35
+ self[:nodes_count].to_i
36
+ end
37
+
38
+ def entry_id
39
+ self[:entry_id]
40
+ end
41
+
42
+ def nodes
43
+ if selectable
44
+ return nil
45
+ end
46
+
47
+ nodes_count > 0 ? [] : nil
48
+ end
49
+
50
+ private
51
+
52
+ def entry_href
53
+ if entry_id.present?
54
+ Engine.routes.url_helpers.edit_entry_path(entry_id, format: :js)
55
+ else
56
+ Engine.routes.url_helpers.select_type_entries_path(self, format: :js)
57
+ end
58
+ end
59
+
60
+ def configs_href
61
+ Engine.routes.url_helpers.config_configs_path(self, format: :json)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,30 @@
1
+ module Flexite
2
+ class Entry < ActiveRecord::Base
3
+ belongs_to :parent, polymorphic: true, touch: true
4
+ attr_accessible :value
5
+ before_save :check_value, :cast_value
6
+
7
+ def view_value
8
+ value.to_s
9
+ end
10
+
11
+ def self.form(attributes = {})
12
+ Form.new(attributes)
13
+ end
14
+
15
+ def self.service(type)
16
+ "entry_#{type}".to_sym
17
+ end
18
+
19
+ alias :form_attributes :attributes
20
+
21
+ private
22
+
23
+ def cast_value
24
+ self[:value] = self[:value].to_s
25
+ end
26
+
27
+ def check_value
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ class Flexite::IntEntry < Flexite::Entry
2
+ def value
3
+ self[:value].to_i
4
+ end
5
+
6
+ private
7
+
8
+ def check_value
9
+ self[:value].to_i
10
+ rescue
11
+ errors.add(:value, 'not an Integer')
12
+ end
13
+ end
@@ -0,0 +1,2 @@
1
+ class Flexite::StrEntry < Flexite::Entry
2
+ end
@@ -0,0 +1,17 @@
1
+ class Flexite::SymEntry < Flexite::Entry
2
+ def value
3
+ self[:value].to_sym
4
+ end
5
+
6
+ def view_value
7
+ ":#{value}"
8
+ end
9
+
10
+ private
11
+
12
+ def check_value
13
+ self[:value].to_sym
14
+ rescue
15
+ errors(:value, 'cannot be casted to Symbol')
16
+ end
17
+ end
@@ -0,0 +1,44 @@
1
+ class Flexite::ActionService::Result
2
+ def initialize(options = {})
3
+ @options = options
4
+ @errors = Hash.new { |h, k| h[k] = [] }
5
+ end
6
+
7
+ def succeed?
8
+ @options.fetch(:succeed, true)
9
+ end
10
+
11
+ def failed?
12
+ !succeed?
13
+ end
14
+
15
+ def render?
16
+ @options.fetch(:render, true)
17
+ end
18
+
19
+ def redirect?
20
+ !render?
21
+ end
22
+
23
+ def data
24
+ @options[:data]
25
+ end
26
+
27
+ alias :record :data
28
+
29
+ def add_error(name, value)
30
+ @errors[name] << value
31
+ end
32
+
33
+ def add_errors(name, values)
34
+ @errors[name] += values
35
+ end
36
+
37
+ def endpoint
38
+ @options.fetch(:endpoint, {})
39
+ end
40
+
41
+ def flash
42
+ @options.fetch(:flash, {})
43
+ end
44
+ end
@@ -0,0 +1,30 @@
1
+ class Flexite::ActionService
2
+ def self.inherited(child)
3
+ child.const_set(:Result, Result)
4
+ end
5
+
6
+ def initialize(form, params = {})
7
+ @form = form
8
+ @params = params
9
+ end
10
+
11
+ def call
12
+ raise NotImplementedError
13
+ end
14
+
15
+ protected
16
+
17
+ def success
18
+ raise NotImplementedError
19
+ end
20
+
21
+ def failure
22
+ raise NotImplementedError
23
+ end
24
+
25
+ def save_errors(result)
26
+ @form.errors.messages.each do |key, values|
27
+ result.add_errors(key, values)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ require_dependency 'flexite/action_service'
2
+
3
+ module Flexite
4
+ class Config::CreateService < ActionService
5
+ def call
6
+ if @form.invalid?
7
+ return failure
8
+ end
9
+
10
+ @record = Config.create(@form.attributes, without_protection: true)
11
+ success
12
+ end
13
+
14
+ protected
15
+
16
+ def failure
17
+ Result.new(success: false, endpoint: { status: 400 })
18
+ end
19
+
20
+ def success
21
+ Result.new(flash: { type: :success, message: 'Config was created!' },
22
+ data: { record: @record })
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ module Flexite
2
+ class Config
3
+ class UpdateService < ActionService
4
+ def call
5
+ if @form.invalid?
6
+ return failure
7
+ end
8
+
9
+ @record = Config.find(@form.id)
10
+ @record.config_id = @form.config_id
11
+ @record.selectable = @form.selectable
12
+ @record.name = @form.name
13
+ @record.save
14
+ success
15
+ end
16
+
17
+ protected
18
+
19
+ def failure
20
+ Result.new(success: false, endpoint: { status: 400 })
21
+ end
22
+
23
+ def success
24
+ Result.new(flash: { type: :success, message: 'Config was updated!' }, data: { record: @record })
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ class Flexite::Data::Hash < Hashie::Mash
2
+ extend Hashie::Extensions::DeepMerge
3
+
4
+ def initialize(*)
5
+ super { |h, k| h[k] = {} }
6
+ end
7
+
8
+ def self.name
9
+ Hash.name
10
+ end
11
+
12
+ class Hashie::Array
13
+ def self.name
14
+ Array.name
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,62 @@
1
+ module Flexite
2
+ class Data::Migrators::Yaml
3
+ def initialize
4
+ @paths = Flexite.config.paths
5
+ @roots = Flexite.config.source_roots
6
+ @hierarchy = Flexite.config.hierarchy
7
+ @data = Data::Hash.new
8
+ end
9
+
10
+ def call
11
+ @paths.each_with_object(@data) do |(name, paths), data|
12
+ paths.each do |p|
13
+ next unless File.exists?(p)
14
+ load_data(data, name, p)
15
+ end
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def load_data(data, name, path)
22
+ with_hierarchy(path) do |configs|
23
+ with_source_roots(data[name], configs, @roots[name])
24
+ end
25
+ end
26
+
27
+ def with_source_roots(data, configs, roots)
28
+ data.deep_merge!(configs) and return if roots.blank?
29
+
30
+ roots.each do |root|
31
+ next if configs[root].blank?
32
+ data.deep_merge!(root => configs[root])
33
+ end
34
+ end
35
+
36
+ # hierarchy = [:a, :b, :c]
37
+ #
38
+ # {
39
+ # a: {
40
+ # b: {
41
+ # c: {}
42
+ # }
43
+ # }
44
+ # }
45
+ #
46
+ #
47
+
48
+ def with_hierarchy(path)
49
+ hierarchy = @hierarchy[path]
50
+ return yield(YAML.load_file(path)) if hierarchy.blank?
51
+
52
+ new_hash = {}
53
+ leveling = new_hash
54
+ hierarchy.each do |level|
55
+ leveling = leveling[level] = {}
56
+ end
57
+
58
+ leveling.merge!(YAML.load_file(path))
59
+ yield(new_hash)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,87 @@
1
+ module Flexite
2
+ class Data::New
3
+ def initialize(migrator)
4
+ @migrator = migrator
5
+ @errors = Hash.new { |h, k| h[k] = [] }
6
+ @result = {}
7
+ end
8
+
9
+ def call
10
+ @migrator.call.each do |root, configs|
11
+ begin
12
+ @result[root] = save_root(root, configs)
13
+ rescue => exc
14
+ @errors[root] << [exc.message, exc.backtrace]
15
+ end
16
+ end
17
+
18
+ @result.tap do |result|
19
+ result[:errors] = @errors
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def save_root(root, configs)
26
+ @result[root] = {}
27
+
28
+ Config.create!(name: root) do |record|
29
+ begin
30
+ save_hash_value(record, configs)
31
+ rescue => exc
32
+ @errors[record] << [exc.message, exc.backtrace]
33
+ end
34
+ end
35
+ end
36
+
37
+ def save_entry(parent, entry)
38
+ send("save_#{entry.class.name.underscore}_value", parent, entry)
39
+ rescue => exc
40
+ @errors[parent] << [exc.message, exc.backtrace]
41
+ end
42
+
43
+ def save_hash_value(parent, hash)
44
+ parent.selectable = false
45
+
46
+ hash.each do |name, value|
47
+ entry = Config.new(name: name)
48
+ save_entry(entry, value)
49
+ parent.configs << entry
50
+ end
51
+ end
52
+
53
+ def save_array_value(parent, array)
54
+ entry = ArrEntry.new
55
+
56
+ array.each do |value|
57
+ save_entry(entry, value)
58
+ end
59
+
60
+ parent.entry = entry
61
+ end
62
+
63
+ def save_symbol_value(parent, symbol)
64
+ parent.entry = SymEntry.new(value: symbol)
65
+ end
66
+
67
+ def save_string_value(parent, string)
68
+ parent.entry = StrEntry.new(value: string)
69
+ end
70
+
71
+ def save_true_class_value(parent, _)
72
+ parent.entry = BoolEntry.new(value: 1)
73
+ end
74
+
75
+ def save_false_class_value(parent, _)
76
+ parent.entry = BoolEntry.new(value: 0)
77
+ end
78
+
79
+ def save_fixnum_value(parent, fixnum)
80
+ parent.entry = IntEntry.new(value: fixnum)
81
+ end
82
+
83
+ def save_nil_class_value(parent, nil_val)
84
+ parent.entry = Entry.new(value: nil_val)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,69 @@
1
+ require_dependency 'flexite/action_service'
2
+
3
+ module Flexite
4
+ class Entry
5
+ class ArrayCreateService < ActionService
6
+ def call
7
+ if @form.invalid?
8
+ return failure
9
+ end
10
+
11
+ process_entry
12
+ end
13
+
14
+ private
15
+
16
+ def process_entry
17
+ @record = ArrEntry.create do |record|
18
+ record.parent_id = @form.parent_id
19
+ record.parent_type = @form.parent_type
20
+ end
21
+
22
+ Entry.transaction do
23
+ create_entries(@form.new_entries, @record.id)
24
+ end
25
+
26
+ success
27
+ rescue => exc
28
+ exc_failure(exc)
29
+ end
30
+
31
+ def create_entries(new_entries, parent_id)
32
+ return if new_entries.blank?
33
+
34
+ new_entries.each do |_, entry|
35
+ if respond_to?("save_#{entry[:type].demodulize.underscore}", true)
36
+ send("save_#{entry[:type].demodulize.underscore}", entry, parent_id)
37
+ else
38
+ save_entry(entry, parent_id)
39
+ end
40
+ end
41
+ end
42
+
43
+ def save_arr_entry(entry, parent_id)
44
+ klass = entry[:type].constantize
45
+ record = klass.create({ parent_id: parent_id, parent_type: klass.base_class.sti_name }, without_protection: true)
46
+ create_entries(entry[:new_entries], record.id)
47
+ end
48
+
49
+ def save_entry(entry, parent_id)
50
+ klass = entry[:type].constantize
51
+ klass.create({ parent_id: parent_id, parent_type: klass.base_class.sti_name, value: entry[:value] }, without_protection: true)
52
+ end
53
+
54
+ protected
55
+
56
+ def failure
57
+ Result.new(success: false, endpoint: { status: 400 })
58
+ end
59
+
60
+ def exc_failure(exc)
61
+ Result.new(success: false, message: exc.message, endpoint: { status: 500 })
62
+ end
63
+
64
+ def success
65
+ Result.new(flash: { type: :success, message: 'Entry was created!' }, data: { record: @record })
66
+ end
67
+ end
68
+ end
69
+ end