rules 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +40 -3
- data/db/migrate/20120831163952_create_rules.rb +1 -2
- data/lib/assets/javascripts/rules/active_admin.js +21 -0
- data/lib/rules.rb +11 -0
- data/lib/rules/config.rb +20 -0
- data/lib/rules/engine.rb +1 -0
- data/lib/rules/evaluators/definitions.rb +4 -2
- data/lib/rules/evaluators/evaluator.rb +8 -2
- data/lib/rules/extensions/active_admin/dsl.rb +32 -31
- data/lib/rules/extensions/active_model/absence_validator.rb +5 -0
- data/lib/rules/extensions/active_model/parameter_key_validator.rb +7 -0
- data/lib/rules/has_rules.rb +1 -1
- data/lib/rules/parameters.rb +1 -1
- data/lib/rules/parameters/attribute.rb +5 -8
- data/lib/rules/parameters/constant.rb +1 -14
- data/lib/rules/parameters/constant_definitions.rb +14 -15
- data/lib/rules/parameters/parameter.rb +39 -13
- data/lib/rules/rule.rb +85 -52
- data/lib/rules/rule_set.rb +53 -50
- data/lib/rules/version.rb +1 -1
- data/spec/dummy/app/assets/images/edit_example.png +0 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/{20120831163952_create_rules.rb → 20121029183622_create_rules.rules.rb} +2 -2
- data/spec/dummy/db/migrate/{20120831173835_create_rule_sets.rb → 20121029183623_create_rule_sets.rules.rb} +1 -0
- data/spec/dummy/db/schema.rb +74 -75
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +8405 -7718
- data/spec/dummy/log/test.log +6158 -282
- data/spec/dummy/script/rails +0 -0
- data/spec/dummy/tmp/cache/assets/C5F/0B0/sprockets%2F7b74141c7941d947343b6d7593e3761e +0 -0
- data/spec/dummy/tmp/cache/assets/C7B/E40/sprockets%2Fc629141780bbee6259a21437c1428a67 +0 -0
- data/spec/dummy/tmp/cache/assets/{C58/950/sprockets%2F615625588c137a1529206d80ee81fe93 → C84/1D0/sprockets%2F649513e42d02d9493f733015c1c8cf58} +0 -0
- data/spec/dummy/tmp/cache/assets/{D0B/EB0/sprockets%2Fa18a9144dadd3f628d2f061f91190d65 → C88/A50/sprockets%2F61269f1f7806037ed104f099517e4b6d} +0 -0
- data/spec/dummy/tmp/cache/assets/{E03/290/sprockets%2Fd469f86939a1cbd52d9b9aaf1db22dae → C9E/670/sprockets%2Ff47927ce03e3b12202e62552e11d911d} +0 -0
- data/spec/dummy/tmp/cache/assets/CAB/910/sprockets%2Fd55a96c4e70110aa337804446dd3983d +0 -0
- data/spec/dummy/tmp/cache/assets/CAE/360/sprockets%2F6039fb610c813f60e634a4782b4aa877 +0 -0
- data/spec/dummy/tmp/cache/assets/CB8/5D0/sprockets%2F5c94c5d562bcb216295496c26397c1d5 +0 -0
- data/spec/dummy/tmp/cache/assets/{CF9/580/sprockets%2F9b6f302133d13906b7d823b4ae14f0aa → CBB/6B0/sprockets%2F81c6f6d9206a39d8743c13c59f461f24} +0 -0
- data/spec/dummy/tmp/cache/assets/{CAD/F70/sprockets%2F5a1855f4cda19a255ffc802226735517 → CBC/7F0/sprockets%2F9c674dfe9e0f6503950e9212602fa198} +0 -0
- data/spec/dummy/tmp/cache/assets/CC4/300/sprockets%2Fc455e0353702d71fea6a99e9988763d2 +0 -0
- data/spec/dummy/tmp/cache/assets/{CA2/8F0/sprockets%2Fa283030e028b24b4ba4084e067888c3e → CCE/540/sprockets%2F7897a2f839c15d27739c478e5098cae3} +0 -0
- data/spec/dummy/tmp/cache/assets/{D11/FD0/sprockets%2Ff7129bbf85d84e8bc056543e20281e3b → CCF/A70/sprockets%2Ff84117614042da23eac1c3c1c95177d5} +0 -0
- data/spec/dummy/tmp/cache/assets/{DCE/350/sprockets%2F812b6c1998c5ad61096ae7b16cdaeeea → CCF/B30/sprockets%2Ff8e4785e47480d99304deb197af77716} +0 -0
- data/spec/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
- data/spec/dummy/tmp/cache/assets/CDB/040/sprockets%2Fc732474e67003a4eb840eb44c5ca9385 +0 -0
- data/spec/dummy/tmp/cache/assets/CE6/210/sprockets%2F65a1063d333cef4cc977b687c063f753 +0 -0
- data/spec/dummy/tmp/cache/assets/{D84/0C0/sprockets%2Fe48907efa9d3370f9a2f687a1a7b8d8d → D03/EA0/sprockets%2F58fba513bbd32d023349c0d57f396c22} +0 -0
- data/spec/dummy/tmp/cache/assets/{DD3/370/sprockets%2Ff23609d51b09058fdd08daeecfd7e5e3 → D1C/C00/sprockets%2Ff3e537b590d1e8c26ba67794ca9a2549} +0 -0
- data/spec/dummy/tmp/cache/assets/{CFE/5D0/sprockets%2F5e63c7f47b86e8916fe1b8f88f470370 → D1E/A20/sprockets%2F448a2575960df5788cb1b6347d9c4bfa} +0 -0
- data/spec/dummy/tmp/cache/assets/{D29/AE0/sprockets%2Fb62ea1b010afb027501b4f18b8dd3689 → D1F/7D0/sprockets%2F39f84da4e78a14f35fc2559b709218cf} +0 -0
- data/spec/dummy/tmp/cache/assets/D30/800/sprockets%2Fb5a31c56ce1b4444a1a1fb826c8881a6 +0 -0
- data/spec/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/spec/dummy/tmp/cache/assets/{CD0/AC0/sprockets%2F6f2c1b921c2b86e16aee3245772240c1 → D37/3D0/sprockets%2F3f693950778fef29f540ccf486789edb} +0 -0
- data/spec/dummy/tmp/cache/assets/D38/540/sprockets%2F86e1ad844bc9df4491a2a52b870421db +0 -0
- data/spec/dummy/tmp/cache/assets/D45/D90/sprockets%2F786ea0631bc7ab5a84183882f07cff7b +0 -0
- data/spec/dummy/tmp/cache/assets/D48/640/sprockets%2F9f4f18d910b678b1d0777e04cdaf6f24 +0 -0
- data/spec/dummy/tmp/cache/assets/{CB8/A30/sprockets%2Ff35759652c08bb7b3921c434d9ee1654 → D4D/0F0/sprockets%2Fe101ce9532cd7f637a3a889fee74291f} +0 -0
- data/spec/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/spec/dummy/tmp/cache/assets/{D72/9E0/sprockets%2Fdf58dccde6a5e1266ba5c386149108c6 → D52/DA0/sprockets%2F36936870fc1855efeb9d8119eec2ee41} +0 -0
- data/spec/dummy/tmp/cache/assets/{D9E/530/sprockets%2F8dbb0027bd9ce6b96c81b82bdec17814 → D54/0D0/sprockets%2F39d86b7fa34888e64af3993acc6e7c10} +0 -0
- data/spec/dummy/tmp/cache/assets/D59/D70/sprockets%2Fed9f0de1b65ae8d7ef89087c83728461 +0 -0
- data/spec/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/spec/dummy/tmp/cache/assets/{D41/AB0/sprockets%2Fd112ea59edbe4b7335549d814cb1d848 → D64/DB0/sprockets%2F7a3fd8bcc2642600f5ce0d5926e5be10} +0 -0
- data/spec/dummy/tmp/cache/assets/D66/7F0/sprockets%2F71eb5b2174c2bca8ed14955fd01c57a7 +0 -0
- data/spec/dummy/tmp/cache/assets/{D47/050/sprockets%2F237eeefd847c43be2e7810a77e80841b → D6F/450/sprockets%2F02efd499574bb3628cec534aee4b11e6} +0 -0
- data/spec/dummy/tmp/cache/assets/D75/770/sprockets%2Fa0501a374162cf29c8a9c8cecf678cf7 +0 -0
- data/spec/dummy/tmp/cache/assets/{C9B/B40/sprockets%2F29dc70cbda38311141464e041655de41 → D78/D80/sprockets%2F9930fb628d6fe577ab5707632a0dffbc} +0 -0
- data/spec/dummy/tmp/cache/assets/D7D/FA0/sprockets%2F4124a7757f7f9ca6ca072ae8ffd3269f +0 -0
- data/spec/dummy/tmp/cache/assets/D8D/970/sprockets%2Fccea3ce5a756eb6e3c61e246c121a730 +0 -0
- data/spec/dummy/tmp/cache/assets/D93/4C0/sprockets%2F857ecd2092cee11f740b3cf2e373ad2a +0 -0
- data/spec/dummy/tmp/cache/assets/{CE4/D80/sprockets%2Fd7f4b155b13ea1d8578693e62b0e6463 → D98/530/sprockets%2F6d51419c03c562d84be5ebfbe71b5a3e} +0 -0
- data/spec/dummy/tmp/cache/assets/D9A/960/sprockets%2F1b481cb0d9ea61f57a341cdc96fc823e +0 -0
- data/spec/dummy/tmp/cache/assets/DA1/DC0/sprockets%2F76c4315e48dbb2cb7e92dd5b8b7ab185 +0 -0
- data/spec/dummy/tmp/cache/assets/{D24/B00/sprockets%2F671d6f261d89a29e918b1ec7818db6a9 → DA5/DE0/sprockets%2F366c4e5e2d81e438b4e50bec5e4d88da} +0 -0
- data/spec/dummy/tmp/cache/assets/{CAC/4A0/sprockets%2F3d00565c9e04f1bd481d33b4f1985706 → DA9/C90/sprockets%2F5bdea8b6a1c99fff81a38fb37281f137} +0 -0
- data/spec/dummy/tmp/cache/assets/{DAA/990/sprockets%2F8e0ca45c660183bfe809afc1f69bf9a9 → DAB/4B0/sprockets%2F9b48d3d915c5ddf603344e595de1fbee} +0 -0
- data/spec/dummy/tmp/cache/assets/DB0/1D0/sprockets%2Fa89dd6f509b6ff2fc8d458d371da2c29 +0 -0
- data/spec/dummy/tmp/cache/assets/{CB2/140/sprockets%2F035ac84d6c64495d0067b926533f8bc3 → DC8/EB0/sprockets%2F8b8dc54ec9133ff2a2b8fc31b1c6da63} +0 -0
- data/spec/dummy/tmp/cache/assets/{D60/6C0/sprockets%2Fd7ef2595e5c50eb96e9d3c3d8698f481 → DD0/170/sprockets%2Fd9eb23a676ff2da1c29e2cb2f0ff4791} +0 -0
- data/spec/dummy/tmp/cache/assets/{D65/EE0/sprockets%2Fd9062d87143bb5c1d9d73c3ea02d7eb1 → DD5/380/sprockets%2Fb835ac5f9225cbc2e3c2c6669df46cee} +0 -0
- data/spec/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/spec/dummy/tmp/cache/assets/DDE/420/sprockets%2Ffb8b186d5bf0307f86f65fc787d2adeb +0 -0
- data/spec/dummy/tmp/cache/assets/DE6/000/sprockets%2F03f0d1a05d0ee270ce8acacef4233bf8 +0 -0
- data/spec/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/spec/dummy/tmp/cache/assets/{ECA/140/sprockets%2Fd8ebea8564753ddfde91fadbdacc9f5b → E21/900/sprockets%2F4013eebd9f4bf6b2870f0d7adbba4e1d} +0 -0
- data/spec/dummy/tmp/cache/sass/{40a0b76d82cd847e80571abbfe75b703bdb6b77f → 2086f86f19c1c7590bd3622023362d065fe06dd4}/active_admin.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{a28435efd4cb26f8ebc9e55bbaf23e3537a13190 → 35fba3f569e02e3ff55b98665f3046be151c4360}/_button.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{a28435efd4cb26f8ebc9e55bbaf23e3537a13190 → 35fba3f569e02e3ff55b98665f3046be151c4360}/_clearfix.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{a28435efd4cb26f8ebc9e55bbaf23e3537a13190 → 35fba3f569e02e3ff55b98665f3046be151c4360}/_font-face.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{a28435efd4cb26f8ebc9e55bbaf23e3537a13190 → 35fba3f569e02e3ff55b98665f3046be151c4360}/_font-family.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{a28435efd4cb26f8ebc9e55bbaf23e3537a13190 → 35fba3f569e02e3ff55b98665f3046be151c4360}/_hide-text.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{a28435efd4cb26f8ebc9e55bbaf23e3537a13190 → 35fba3f569e02e3ff55b98665f3046be151c4360}/_html5-input-types.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{a28435efd4cb26f8ebc9e55bbaf23e3537a13190 → 35fba3f569e02e3ff55b98665f3046be151c4360}/_position.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{a28435efd4cb26f8ebc9e55bbaf23e3537a13190 → 35fba3f569e02e3ff55b98665f3046be151c4360}/_timing-functions.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{ee5b745f862b39ff22bf2068a6582c3ee05d1a79 → 4498c5797b40d28956767b90fa545e9739e43edc}/_dashboard.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{ee5b745f862b39ff22bf2068a6582c3ee05d1a79 → 4498c5797b40d28956767b90fa545e9739e43edc}/_logged_out.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{597823364192c14f6a72ee20d1a1496a722ab1f2 → 4c643142bab3f2738bc6b6f785180a24ac1b79de}/_all.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{597823364192c14f6a72ee20d1a1496a722ab1f2 → 4c643142bab3f2738bc6b6f785180a24ac1b79de}/_buttons.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{597823364192c14f6a72ee20d1a1496a722ab1f2 → 4c643142bab3f2738bc6b6f785180a24ac1b79de}/_gradients.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{597823364192c14f6a72ee20d1a1496a722ab1f2 → 4c643142bab3f2738bc6b6f785180a24ac1b79de}/_icons.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{597823364192c14f6a72ee20d1a1496a722ab1f2 → 4c643142bab3f2738bc6b6f785180a24ac1b79de}/_reset.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{597823364192c14f6a72ee20d1a1496a722ab1f2 → 4c643142bab3f2738bc6b6f785180a24ac1b79de}/_rounded.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{597823364192c14f6a72ee20d1a1496a722ab1f2 → 4c643142bab3f2738bc6b6f785180a24ac1b79de}/_sections.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{597823364192c14f6a72ee20d1a1496a722ab1f2 → 4c643142bab3f2738bc6b6f785180a24ac1b79de}/_shadows.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{597823364192c14f6a72ee20d1a1496a722ab1f2 → 4c643142bab3f2738bc6b6f785180a24ac1b79de}/_typography.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{597823364192c14f6a72ee20d1a1496a722ab1f2 → 4c643142bab3f2738bc6b6f785180a24ac1b79de}/_utilities.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{597823364192c14f6a72ee20d1a1496a722ab1f2 → 4c643142bab3f2738bc6b6f785180a24ac1b79de}/_variables.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_batch_actions.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_blank_slates.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_breadcrumbs.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_buttons.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_columns.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_comments.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_date_picker.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_dropdown_menu.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_flash_messages.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_grid.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_links.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_pagination.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_panels.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_popovers.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_scopes.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_status_tags.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_table_tools.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{7f31076cc0ed50f35bd0098f8e2a34720ee15633 → 5d62cb9b998e0464beef8c02d6cedb219bafb98d}/_tables.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{bb2f93296c9b1e89237438ea63572f38aae290c3 → 9f77ade2a538829418bc2e2168a13e3c5e8d566e}/_deprecated-webkit-gradient.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{bb2f93296c9b1e89237438ea63572f38aae290c3 → 9f77ade2a538829418bc2e2168a13e3c5e8d566e}/_flex-grid.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{bb2f93296c9b1e89237438ea63572f38aae290c3 → 9f77ade2a538829418bc2e2168a13e3c5e8d566e}/_grid-width.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{bb2f93296c9b1e89237438ea63572f38aae290c3 → 9f77ade2a538829418bc2e2168a13e3c5e8d566e}/_linear-gradient.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{bb2f93296c9b1e89237438ea63572f38aae290c3 → 9f77ade2a538829418bc2e2168a13e3c5e8d566e}/_modular-scale.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{bb2f93296c9b1e89237438ea63572f38aae290c3 → 9f77ade2a538829418bc2e2168a13e3c5e8d566e}/_radial-gradient.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{bb2f93296c9b1e89237438ea63572f38aae290c3 → 9f77ade2a538829418bc2e2168a13e3c5e8d566e}/_render-gradients.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{bb2f93296c9b1e89237438ea63572f38aae290c3 → 9f77ade2a538829418bc2e2168a13e3c5e8d566e}/_tint-shade.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{bb2f93296c9b1e89237438ea63572f38aae290c3 → 9f77ade2a538829418bc2e2168a13e3c5e8d566e}/_transition-property-name.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{1a9fc2ebd62e6e7cb58441dc0293552ac07c99a9 → a500b9d7e9e6288c20d3d089871d43ac3aee2604}/_bourbon.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_animation.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_appearance.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_background-image.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_background-size.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_background.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_border-image.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_border-radius.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_box-shadow.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_box-sizing.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_columns.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_flex-box.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_inline-block.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_linear-gradient.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_prefixer.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_radial-gradient.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_transform.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_transition.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{da77e6f9a782ec4d4cbe7e3a439e89684c300b51 → b44994b8f6b8597cac35b9d162a52f9cd517eda4}/_user-select.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{6d594ee297c7ebeecae08432451ce722569d1a35 → d39759080a3787a3183222f58ca8294b28eca502}/_footer.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{6d594ee297c7ebeecae08432451ce722569d1a35 → d39759080a3787a3183222f58ca8294b28eca502}/_main_structure.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{6d594ee297c7ebeecae08432451ce722569d1a35 → d39759080a3787a3183222f58ca8294b28eca502}/_title_bar.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{89a136914378618e18c0f75bc8c0f78e84403b0f → ecc4c9317361a12ede9a49c29635837608d17540}/_base.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{89a136914378618e18c0f75bc8c0f78e84403b0f → ecc4c9317361a12ede9a49c29635837608d17540}/_forms.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{89a136914378618e18c0f75bc8c0f78e84403b0f → ecc4c9317361a12ede9a49c29635837608d17540}/_header.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{89a136914378618e18c0f75bc8c0f78e84403b0f → ecc4c9317361a12ede9a49c29635837608d17540}/_mixins.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{89a136914378618e18c0f75bc8c0f78e84403b0f → ecc4c9317361a12ede9a49c29635837608d17540}/_typography.css.scssc +0 -0
- data/spec/dummy/tmp/cache/sass/{89a136914378618e18c0f75bc8c0f78e84403b0f → ecc4c9317361a12ede9a49c29635837608d17540}/print.css.scssc +0 -0
- data/spec/rules/evaluators/evaluator_spec.rb +36 -0
- data/spec/rules/parameters/attribute_spec.rb +20 -0
- data/spec/rules/rule_set_spec.rb +21 -11
- data/spec/rules/rule_spec.rb +138 -65
- metadata +262 -289
- data/spec/dummy/db/production.sqlite3 +0 -0
- data/spec/dummy/log/production.log +0 -74
- data/spec/dummy/tmp/cache/assets/C83/FF0/sprockets%2F75b536e9b6927c15b60310fa867e3613 +0 -0
- data/spec/dummy/tmp/cache/assets/C88/FD0/sprockets%2F6c558405457e9b59062515dc86bfa252 +0 -0
- data/spec/dummy/tmp/cache/assets/C99/A50/sprockets%2Ffd135176f584f5f5658ef48f41187352 +0 -0
- data/spec/dummy/tmp/cache/assets/C9F/2F0/sprockets%2Faf814c1513450b5466432d2a565ca5c6 +0 -0
- data/spec/dummy/tmp/cache/assets/CA7/860/sprockets%2F0b1c90a9344b3c3989fc2153d0d63193 +0 -0
- data/spec/dummy/tmp/cache/assets/CAE/DA0/sprockets%2F9a133e6ab132f569c40b5e82188f4290 +0 -0
- data/spec/dummy/tmp/cache/assets/CB2/920/sprockets%2F2db5288c0689b237264d0fb22b74d981 +0 -0
- data/spec/dummy/tmp/cache/assets/CCA/AE0/sprockets%2Ff80b892078268a51ddf973986035bf9d +0 -0
- data/spec/dummy/tmp/cache/assets/CE0/300/sprockets%2F79b0286bc0a316d639ed5f83b1d33763 +0 -0
- data/spec/dummy/tmp/cache/assets/CFD/B50/sprockets%2Fb21fb4d7213b3bf64d6317b3f22584b1 +0 -0
- data/spec/dummy/tmp/cache/assets/CFE/450/sprockets%2F088e843f7fffd845821822c7668a4d7e +0 -0
- data/spec/dummy/tmp/cache/assets/CFE/D50/sprockets%2Fc912074248a7b0bdc219a5eac3c52348 +0 -0
- data/spec/dummy/tmp/cache/assets/D0B/650/sprockets%2Fb66b60c6b42330849f5b7449bbe108bd +0 -0
- data/spec/dummy/tmp/cache/assets/D0E/820/sprockets%2F1611a9cc354f4e02c97d26b3c6ce7466 +0 -0
- data/spec/dummy/tmp/cache/assets/D38/5F0/sprockets%2F0c09a45e38408ec6e0e9caf206d5028d +0 -0
- data/spec/dummy/tmp/cache/assets/D3A/CE0/sprockets%2F238bf80bfbe1e2a5bb9280e62162584f +0 -0
- data/spec/dummy/tmp/cache/assets/D3B/000/sprockets%2F961758db39c6223d18ea6b7aeac400d5 +0 -0
- data/spec/dummy/tmp/cache/assets/D3B/F60/sprockets%2Ffd56cbfde039018718a0933340af6ef2 +0 -0
- data/spec/dummy/tmp/cache/assets/D48/0D0/sprockets%2F1ef4ab19f690478ac62ad77fcb284447 +0 -0
- data/spec/dummy/tmp/cache/assets/D65/B10/sprockets%2Fca02dba972b587d3a69b8c32c7200fc6 +0 -0
- data/spec/dummy/tmp/cache/assets/D66/2A0/sprockets%2F7b7cb56109acc9205fbbb792187ad04b +0 -0
- data/spec/dummy/tmp/cache/assets/D94/FA0/sprockets%2F8b190b3f72af75f09bfab1f354a0c37b +0 -0
- data/spec/dummy/tmp/cache/assets/D98/550/sprockets%2F69a91a7b4aca241c17daf6a78ac6845a +0 -0
- data/spec/dummy/tmp/cache/assets/DC1/C40/sprockets%2Fa8cbeabf3ef2d34b43be61671536f2a2 +0 -0
- data/spec/dummy/tmp/cache/assets/DC7/8B0/sprockets%2Ffad93382facdc50f097e26ebf19010ea +0 -0
- data/spec/dummy/tmp/cache/assets/DD7/6A0/sprockets%2Fd5b1cca8d0835fbe9957aa4ee5f8333e +0 -0
- data/spec/dummy/tmp/cache/assets/DD8/440/sprockets%2F7edf42cfb3ac43c7cd4f63c3980d7c86 +0 -0
- data/spec/dummy/tmp/cache/assets/DF5/270/sprockets%2Fc7f64f609aceac43da16557daacc421f +0 -0
- data/spec/dummy/tmp/cache/assets/DF5/410/sprockets%2Fd6efccfb4bfeb13ed0125e8c53424a65 +0 -0
- data/spec/dummy/tmp/cache/assets/DFF/180/sprockets%2Fdc24014f1fcc77f40c5e7de188ad8ebd +0 -0
- data/spec/dummy/tmp/cache/assets/E07/7C0/sprockets%2Fcc5def6ed69cb6a1b7f6084992ed3ca1 +0 -0
- data/spec/dummy/tmp/pids/server.pid +0 -1
data/README.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
1
|
+
Rules
|
2
2
|
=========
|
3
|
+
[![build status](https://secure.travis-ci.org/azach/rules.png?branch=master)](https://secure.travis-ci.org/azach/rules) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/azach/rules)
|
3
4
|
|
4
5
|
A Ruby gem engine that allows you to add customizable business rules to any ActiveRecord model. Rules integrates with ActiveAdmin to make it trivial to allow admin users to create rules on the fly for your models.
|
5
6
|
|
@@ -8,7 +9,7 @@ Installation
|
|
8
9
|
Add it to your Gemfile:
|
9
10
|
|
10
11
|
```ruby
|
11
|
-
gem "rules"
|
12
|
+
gem "rules"
|
12
13
|
```
|
13
14
|
|
14
15
|
Update your schema:
|
@@ -33,6 +34,7 @@ class Order < ActiveRecord::Base
|
|
33
34
|
has_rule_attributes({
|
34
35
|
customer_email: {
|
35
36
|
name: "customer email address"
|
37
|
+
type: :string # see Rules::Parameters::Parameter::VALID_TYPES for a full list
|
36
38
|
}
|
37
39
|
})
|
38
40
|
end
|
@@ -45,7 +47,7 @@ For example:
|
|
45
47
|
```ruby
|
46
48
|
order = Order.new
|
47
49
|
order.email_address = "morbo@example.com"
|
48
|
-
order.
|
50
|
+
order.rules_pass?(customer_email: order.email_address)
|
49
51
|
```
|
50
52
|
|
51
53
|
Defining Rules
|
@@ -70,6 +72,41 @@ This will give you something like:
|
|
70
72
|
|
71
73
|
![ActiveAdmin form for editing rules](https://github.com/azach/rules/raw/master/spec/dummy/app/assets/images/edit_example.png)
|
72
74
|
|
75
|
+
However, rules are defined using keys and values, so you can easily use your own custom solution.
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
rule = Rules::Rule.new(lhs_parameter_key: 'day_of_week', evaluator_key: 'equals', rhs_parameter_raw: 'Sunday')
|
79
|
+
rule.lhs_parameter_value
|
80
|
+
=> 'Sunday' # (or the current day of week)
|
81
|
+
rule.evaluate
|
82
|
+
=> true
|
83
|
+
|
84
|
+
Order.has_rule_attributes(customer_email: { name: "Customer's email address" })
|
85
|
+
order = Order.new
|
86
|
+
rule_set = Rules::RuleSet.new(source: order)
|
87
|
+
|
88
|
+
rule = Rules::Rule.new(rule_set: rule_set, lhs_parameter_key: 'customer_email', evaluator_key: 'matches', rhs_parameter_raw: 'example.com$')
|
89
|
+
rule.lhs_parameter_value
|
90
|
+
=> nil # we didn't pass anything in
|
91
|
+
rule.rhs_parameter_value
|
92
|
+
=> /example.com$/ # this is a Regexp class
|
93
|
+
rule.evaluate(customer_email: 'john@example.com')
|
94
|
+
=> true
|
95
|
+
rule.evaluate(customer_email: 'john@example.net')
|
96
|
+
=> false
|
97
|
+
```
|
98
|
+
|
99
|
+
Configuration
|
100
|
+
------------
|
101
|
+
You can add an initializer to configure default options.
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
Rules.configure do |config|
|
105
|
+
config.errors_are_false = true # return false if an evaluator raises an error (true by default)
|
106
|
+
config.missing_attributes_are_nil = true # return nil when a value is not passed for an attribute parameter
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
73
110
|
Default Constants
|
74
111
|
------------
|
75
112
|
TODO
|
@@ -0,0 +1,21 @@
|
|
1
|
+
$(function() {
|
2
|
+
$('.rules_rule_set select[name*="[lhs_parameter_key]"]').on('change', function(ev) {
|
3
|
+
var $rawInput;
|
4
|
+
var selectedType;
|
5
|
+
|
6
|
+
$rawInput = $(this).parent('li').siblings('[id*="rhs_parameter_raw_input"]').find('input');
|
7
|
+
selectedType = $(this).find(':selected').data('type');
|
8
|
+
|
9
|
+
$rawInput.get(0).type = selectedType;
|
10
|
+
});
|
11
|
+
|
12
|
+
$('.rules_rule_set select[name*="[evaluator_key]"]').on('change', function(ev) {
|
13
|
+
var $rhsInputs;
|
14
|
+
var requiresRHS;
|
15
|
+
|
16
|
+
$rawInputs = $(this).parent('li').siblings('[id*="rhs_parameter"]').find('input, select');
|
17
|
+
requiresRHS = $(this).find(':selected').data('requires-rhs');
|
18
|
+
|
19
|
+
$rawInputs.prop('disabled', !requiresRHS);
|
20
|
+
});
|
21
|
+
});
|
data/lib/rules.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
require 'rules/engine'
|
2
|
+
require 'rules/extensions/active_model/absence_validator'
|
3
|
+
require 'rules/extensions/active_model/parameter_key_validator'
|
4
|
+
require 'rules/config'
|
2
5
|
require 'rules/evaluators'
|
3
6
|
require 'rules/evaluators/definitions'
|
4
7
|
require 'rules/has_rules'
|
@@ -8,6 +11,14 @@ require 'rules/rule'
|
|
8
11
|
require 'rules/rule_set'
|
9
12
|
|
10
13
|
module Rules
|
14
|
+
def self.config
|
15
|
+
@config ||= Config.instance
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.configure
|
19
|
+
yield config
|
20
|
+
end
|
21
|
+
|
11
22
|
def self.evaluators
|
12
23
|
@evaluators ||= Evaluators.list
|
13
24
|
end
|
data/lib/rules/config.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
class Rules::Config
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
attr_accessor :errors_are_false, :missing_attributes_are_nil
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
self.errors_are_false = true
|
10
|
+
self.missing_attributes_are_nil = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def missing_attributes_are_nil?
|
14
|
+
!!missing_attributes_are_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def errors_are_false?
|
18
|
+
!!errors_are_false
|
19
|
+
end
|
20
|
+
end
|
data/lib/rules/engine.rb
CHANGED
@@ -35,14 +35,16 @@ module Rules
|
|
35
35
|
end
|
36
36
|
|
37
37
|
define_evaluator :matches do
|
38
|
-
self.evaluation_method = ->(lhs, rhs) { !!(lhs =~
|
38
|
+
self.evaluation_method = ->(lhs, rhs) { !!(lhs =~ rhs) }
|
39
39
|
self.name = 'matches'
|
40
|
+
self.type_for_rhs = :regexp
|
40
41
|
self.requires_rhs = true
|
41
42
|
end
|
42
43
|
|
43
44
|
define_evaluator :not_matches do
|
44
|
-
self.evaluation_method = ->(lhs, rhs) { !(lhs =~
|
45
|
+
self.evaluation_method = ->(lhs, rhs) { !(lhs =~ rhs) }
|
45
46
|
self.name = 'does not match'
|
47
|
+
self.type_for_rhs = :regexp
|
46
48
|
self.requires_rhs = true
|
47
49
|
end
|
48
50
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Rules
|
2
2
|
module Evaluators
|
3
3
|
class Evaluator
|
4
|
-
attr_accessor :evaluation_method, :requires_rhs, :name
|
4
|
+
attr_accessor :evaluation_method, :requires_rhs, :type_for_rhs, :name
|
5
5
|
|
6
6
|
def initialize(key)
|
7
7
|
@name = key.to_s
|
@@ -10,7 +10,13 @@ module Rules
|
|
10
10
|
|
11
11
|
def evaluate(lhs, rhs = nil)
|
12
12
|
raise 'Unknown evaluation method' unless evaluation_method
|
13
|
-
|
13
|
+
|
14
|
+
begin
|
15
|
+
requires_rhs? ? evaluation_method.call(lhs, rhs) : evaluation_method.call(lhs)
|
16
|
+
rescue StandardError => ex
|
17
|
+
return false if Rules.config.errors_are_false?
|
18
|
+
raise ex
|
19
|
+
end
|
14
20
|
end
|
15
21
|
|
16
22
|
def requires_rhs?
|
@@ -1,31 +1,32 @@
|
|
1
|
-
ActiveAdmin::FormBuilder.class_eval do
|
2
|
-
def has_rules
|
3
|
-
|
4
|
-
|
5
|
-
rules_rule_set_form.has_many :rules do |rules_rule_form|
|
6
|
-
rules_rule_form.input :
|
7
|
-
rules_rule_form.input :
|
8
|
-
rules_rule_form.input :
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
column('
|
27
|
-
column('
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
1
|
+
ActiveAdmin::FormBuilder.class_eval do
|
2
|
+
def has_rules
|
3
|
+
inputs 'Rules' do
|
4
|
+
semantic_fields_for :rule_set do |rules_rule_set_form|
|
5
|
+
rules_rule_set_form.has_many :rules do |rules_rule_form|
|
6
|
+
rules_rule_form.input :lhs_parameter_key, :label => 'Left hand side', collection: rules_parameter_collection(object.rule_set)
|
7
|
+
rules_rule_form.input :evaluator_key, :label => 'Evaluator', :as => :select, :collection => Rules.evaluators.map {|key, evaluator| [evaluator.name, key, {:'data-requires-rhs' => evaluator.requires_rhs?}] }.sort_by {|name, key| name }
|
8
|
+
rules_rule_form.input :rhs_parameter_raw, :label => 'Enter a value', :wrapper_html => { :class => "rules_rhs_parameter" }
|
9
|
+
rules_rule_form.input :rhs_parameter_key, :label => 'Or choose a value', collection: rules_parameter_collection(object.rule_set), :wrapper_html => { :class => "rules_rhs_parameter" }
|
10
|
+
end
|
11
|
+
rules_rule_set_form.input :evaluation_logic, :as => :select, :label => 'Must match', collection: [['All Rules', 'all'], ['Any Rules', 'any']]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def rules_parameter_collection(rule_set)
|
17
|
+
@rules_parameter_collection ||= Rules.constants.merge(rule_set.try(:attributes) || {}).map {|key, const| [const.name, key, {:'data-type' => const.try(:type) || 'string'}] }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
ActiveAdmin::Views::Pages::Show.class_eval do
|
22
|
+
def show_rules
|
23
|
+
panel "Rules" do
|
24
|
+
div resource.rule_set.evaluation_logic == 'any' ? 'Must match any rule' : 'Must match all rules'
|
25
|
+
table_for resource.rule_set.rules do |rule|
|
26
|
+
column('Left hand side') { |rule| rule.lhs_parameter.to_s }
|
27
|
+
column('Condition') { |rule| rule.evaluator }
|
28
|
+
column('Right hand side') { |rule| rule.rhs_parameter.to_s }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/rules/has_rules.rb
CHANGED
data/lib/rules/parameters.rb
CHANGED
@@ -12,7 +12,7 @@ module Rules
|
|
12
12
|
|
13
13
|
def self.define_constant(key, &block)
|
14
14
|
raise "Constant #{key} already exists" if @@constants[key]
|
15
|
-
constant = Constant.new(key)
|
15
|
+
constant = Constant.new(key: key)
|
16
16
|
constant.instance_eval(&block) if block_given?
|
17
17
|
@@constants[key] = constant
|
18
18
|
end
|
@@ -2,15 +2,12 @@ require 'rules/parameters/parameter'
|
|
2
2
|
|
3
3
|
module Rules::Parameters
|
4
4
|
class Attribute < Parameter
|
5
|
-
attr_reader :key
|
6
|
-
|
7
|
-
def initialize(options = {})
|
8
|
-
@name = options[:name]
|
9
|
-
@key = options[:key].to_sym
|
10
|
-
end
|
11
|
-
|
12
5
|
def evaluate(attributes = {})
|
13
|
-
|
6
|
+
if Rules.config.missing_attributes_are_nil?
|
7
|
+
attributes[key]
|
8
|
+
else
|
9
|
+
attributes.fetch(key)
|
10
|
+
end
|
14
11
|
end
|
15
12
|
end
|
16
13
|
end
|
@@ -2,24 +2,11 @@ require 'rules/parameters/parameter'
|
|
2
2
|
|
3
3
|
module Rules::Parameters
|
4
4
|
class Constant < Parameter
|
5
|
-
attr_accessor :evaluation_method
|
6
|
-
|
7
|
-
def initialize(key)
|
8
|
-
self.name = key.to_s
|
9
|
-
end
|
5
|
+
attr_accessor :evaluation_method
|
10
6
|
|
11
7
|
def evaluate(attributes = {})
|
12
8
|
raise 'Unknown evaluation method' unless evaluation_method
|
13
9
|
evaluation_method.call
|
14
10
|
end
|
15
|
-
|
16
|
-
def input_type
|
17
|
-
@input_type || :string
|
18
|
-
end
|
19
|
-
|
20
|
-
def cast(value)
|
21
|
-
return value unless casting_method
|
22
|
-
casting_method.call(value)
|
23
|
-
end
|
24
11
|
end
|
25
12
|
end
|
@@ -1,15 +1,14 @@
|
|
1
|
-
module Rules
|
2
|
-
module Parameters
|
3
|
-
define_constant :today do
|
4
|
-
self.name = 'current date'
|
5
|
-
self.
|
6
|
-
self.evaluation_method = -> { Time.now.utc.to_date }
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
self.
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
1
|
+
module Rules
|
2
|
+
module Parameters
|
3
|
+
define_constant :today do
|
4
|
+
self.name = 'current date'
|
5
|
+
self.type = :date
|
6
|
+
self.evaluation_method = -> { Time.now.utc.to_date }
|
7
|
+
end
|
8
|
+
|
9
|
+
define_constant :day_of_week do
|
10
|
+
self.name = 'day of week'
|
11
|
+
self.evaluation_method = -> { Date::DAYNAMES[Time.now.utc.to_date.wday] }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,13 +1,39 @@
|
|
1
|
-
module Rules::Parameters
|
2
|
-
class Parameter
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
1
|
+
module Rules::Parameters
|
2
|
+
class Parameter
|
3
|
+
VALID_TYPES = [:date, :integer, :float, :boolean, :string, :regexp]
|
4
|
+
|
5
|
+
attr_accessor :name, :type, :key
|
6
|
+
|
7
|
+
def self.cast(value, type)
|
8
|
+
return value unless type
|
9
|
+
case type
|
10
|
+
when :date
|
11
|
+
Date.parse(value.to_s)
|
12
|
+
when :integer
|
13
|
+
value.to_i
|
14
|
+
when :float
|
15
|
+
value.to_f
|
16
|
+
when :boolean
|
17
|
+
value.to_s == 'true' ? true : false
|
18
|
+
when :string
|
19
|
+
value.to_s
|
20
|
+
when :regexp
|
21
|
+
Regexp.new(value.to_s)
|
22
|
+
else
|
23
|
+
raise "Don't know how to cast #{type}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(options = {})
|
28
|
+
self.key = options[:key].to_sym
|
29
|
+
self.name = options[:name] || options[:key].to_s.humanize
|
30
|
+
self.type = options[:type] if options[:type]
|
31
|
+
|
32
|
+
raise "Unknown type #{type}" if type && !VALID_TYPES.include?(type)
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/rules/rule.rb
CHANGED
@@ -1,52 +1,85 @@
|
|
1
|
-
require 'rules/evaluators'
|
2
|
-
require 'rules/parameters'
|
3
|
-
|
4
|
-
module Rules
|
5
|
-
class Rule < ActiveRecord::Base
|
6
|
-
attr_accessible :rule_set, :
|
7
|
-
|
8
|
-
belongs_to :rule_set, class_name: 'Rules::RuleSet'
|
9
|
-
|
10
|
-
validates :
|
11
|
-
validates :
|
12
|
-
validates :
|
13
|
-
validates :
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
1
|
+
require 'rules/evaluators'
|
2
|
+
require 'rules/parameters'
|
3
|
+
|
4
|
+
module Rules
|
5
|
+
class Rule < ActiveRecord::Base
|
6
|
+
attr_accessible :rule_set, :evaluator_key, :lhs_parameter_key, :rhs_parameter_key, :rhs_parameter_raw
|
7
|
+
|
8
|
+
belongs_to :rule_set, class_name: 'Rules::RuleSet'
|
9
|
+
|
10
|
+
validates :evaluator_key, presence: true, inclusion: {in: Evaluators.list.keys.map(&:to_s)}
|
11
|
+
validates :lhs_parameter_key, parameter_key: true
|
12
|
+
validates :rhs_parameter_key, parameter_key: true, if: :rhs_parameter_key
|
13
|
+
validates :rhs_parameter_key, presence: true, if: :requires_rhs?, unless: :rhs_parameter_raw
|
14
|
+
validates :rhs_parameter_key, absence: true, unless: :requires_rhs?
|
15
|
+
validates :rhs_parameter_raw, absence: true, unless: :requires_rhs?
|
16
|
+
validates :rhs_parameter_key, absence: true, if: :rhs_parameter_raw
|
17
|
+
|
18
|
+
store :expression, :accessors => [:evaluator_key, :lhs_parameter_key, :rhs_parameter_key, :rhs_parameter_raw]
|
19
|
+
|
20
|
+
def evaluate(attributes = {})
|
21
|
+
lhv = lhs_parameter_value(attributes)
|
22
|
+
rhv = rhs_parameter_value(attributes) if evaluator.requires_rhs?
|
23
|
+
evaluator.evaluate(lhv, rhv)
|
24
|
+
end
|
25
|
+
|
26
|
+
def evaluator
|
27
|
+
@evaluator ||= evaluator_key ? Evaluators.list[evaluator_key.to_sym] : nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def lhs_parameter_key
|
31
|
+
key_from_store :lhs_parameter_key
|
32
|
+
end
|
33
|
+
|
34
|
+
def rhs_parameter_key
|
35
|
+
key_from_store :rhs_parameter_key
|
36
|
+
end
|
37
|
+
|
38
|
+
def evaluator_key
|
39
|
+
key_from_store :evaluator_key
|
40
|
+
end
|
41
|
+
|
42
|
+
def lhs_parameter_value(attributes = {})
|
43
|
+
lhs_parameter.try(:evaluate, attributes)
|
44
|
+
end
|
45
|
+
|
46
|
+
def rhs_parameter_value(attributes = {})
|
47
|
+
if rhs_parameter.respond_to?(:evaluate)
|
48
|
+
rhs_parameter.try(:evaluate, attributes)
|
49
|
+
else
|
50
|
+
rhv = Parameters::Parameter.cast(rhs_parameter_raw, lhs_parameter.try(:type))
|
51
|
+
Parameters::Parameter.cast(rhv, evaluator.try(:type_for_rhs))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def rhs_parameter
|
56
|
+
rhs_parameter_key ? parameter_from_key(rhs_parameter_key) : rhs_parameter_raw
|
57
|
+
end
|
58
|
+
|
59
|
+
def lhs_parameter
|
60
|
+
@lhs_parameter ||= lhs_parameter_key ? parameter_from_key(lhs_parameter_key) : nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def valid_parameter_keys
|
64
|
+
Parameters.constants.keys.map(&:to_s) + valid_attributes.keys.map(&:to_s)
|
65
|
+
end
|
66
|
+
|
67
|
+
def valid_attributes
|
68
|
+
rule_set ? rule_set.attributes : {}
|
69
|
+
end
|
70
|
+
|
71
|
+
def requires_rhs?
|
72
|
+
evaluator ? evaluator.requires_rhs? : false
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def key_from_store(key)
|
78
|
+
expression[key].blank? ? nil : expression[key]
|
79
|
+
end
|
80
|
+
|
81
|
+
def parameter_from_key(key)
|
82
|
+
Parameters.constants[key.to_sym] || valid_attributes[key.to_sym]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|